VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevHda.cpp@ 90134

Last change on this file since 90134 was 90134, checked in by vboxsync, 4 years ago

DevHda: Consolidating codec state into one structure and removing the unnecessary R3 codec state allocating. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 213.3 KB
Line 
1/* $Id: DevHda.cpp 90134 2021-07-09 16:57:39Z vboxsync $ */
2/** @file
3 * Intel HD Audio Controller Emulation.
4 *
5 * Implemented against the specifications found in "High Definition Audio
6 * Specification", Revision 1.0a June 17, 2010, and "Intel I/O Controller
7 * HUB 6 (ICH6) Family, Datasheet", document number 301473-002.
8 */
9
10/*
11 * Copyright (C) 2006-2020 Oracle Corporation
12 *
13 * This file is part of VirtualBox Open Source Edition (OSE), as
14 * available from http://www.virtualbox.org. This file is free software;
15 * you can redistribute it and/or modify it under the terms of the GNU
16 * General Public License (GPL) as published by the Free Software
17 * Foundation, in version 2 as it comes in the "COPYING" file of the
18 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20 */
21
22
23/*********************************************************************************************************************************
24* Header Files *
25*********************************************************************************************************************************/
26#define LOG_GROUP LOG_GROUP_DEV_HDA
27#include <VBox/log.h>
28
29#include <VBox/vmm/pdmdev.h>
30#include <VBox/vmm/pdmaudioifs.h>
31#include <VBox/vmm/pdmaudioinline.h>
32#ifdef HDA_DEBUG_GUEST_RIP
33# include <VBox/vmm/cpum.h>
34#endif
35#include <VBox/version.h>
36#include <VBox/AssertGuest.h>
37
38#include <iprt/assert.h>
39#include <iprt/asm.h>
40#include <iprt/asm-math.h>
41#include <iprt/file.h>
42#include <iprt/list.h>
43# include <iprt/string.h>
44#ifdef IN_RING3
45# include <iprt/mem.h>
46# include <iprt/semaphore.h>
47# include <iprt/uuid.h>
48#endif
49
50#include "VBoxDD.h"
51
52#include "AudioMixBuffer.h"
53#include "AudioMixer.h"
54
55#define VBOX_HDA_CAN_ACCESS_REG_MAP /* g_aHdaRegMap is accessible */
56#include "DevHda.h"
57
58#include "AudioHlp.h"
59
60
61/*********************************************************************************************************************************
62* Defined Constants And Macros *
63*********************************************************************************************************************************/
64#if defined(VBOX_WITH_HP_HDA)
65/* HP Pavilion dv4t-1300 */
66# define HDA_PCI_VENDOR_ID 0x103c
67# define HDA_PCI_DEVICE_ID 0x30f7
68#elif defined(VBOX_WITH_INTEL_HDA)
69/* Intel HDA controller */
70# define HDA_PCI_VENDOR_ID 0x8086
71# define HDA_PCI_DEVICE_ID 0x2668
72#elif defined(VBOX_WITH_NVIDIA_HDA)
73/* nVidia HDA controller */
74# define HDA_PCI_VENDOR_ID 0x10de
75# define HDA_PCI_DEVICE_ID 0x0ac0
76#else
77# error "Please specify your HDA device vendor/device IDs"
78#endif
79
80/**
81 * Acquires the HDA lock.
82 */
83#define DEVHDA_LOCK(a_pDevIns, a_pThis) \
84 do { \
85 int rcLock = PDMDevHlpCritSectEnter((a_pDevIns), &(a_pThis)->CritSect, VERR_IGNORED); \
86 AssertRC(rcLock); \
87 } while (0)
88
89/**
90 * Acquires the HDA lock or returns.
91 */
92#define DEVHDA_LOCK_RETURN(a_pDevIns, a_pThis, a_rcBusy) \
93 do { \
94 int rcLock = PDMDevHlpCritSectEnter((a_pDevIns), &(a_pThis)->CritSect, a_rcBusy); \
95 if (rcLock == VINF_SUCCESS) \
96 { /* likely */ } \
97 else \
98 { \
99 AssertRC(rcLock); \
100 return rcLock; \
101 } \
102 } while (0)
103
104/**
105 * Acquires the HDA lock or returns.
106 */
107# define DEVHDA_LOCK_RETURN_VOID(a_pDevIns, a_pThis) \
108 do { \
109 int rcLock = PDMDevHlpCritSectEnter((a_pDevIns), &(a_pThis)->CritSect, VERR_IGNORED); \
110 if (rcLock == VINF_SUCCESS) \
111 { /* likely */ } \
112 else \
113 { \
114 AssertRC(rcLock); \
115 return; \
116 } \
117 } while (0)
118
119/**
120 * Releases the HDA lock.
121 */
122#define DEVHDA_UNLOCK(a_pDevIns, a_pThis) \
123 do { PDMDevHlpCritSectLeave((a_pDevIns), &(a_pThis)->CritSect); } while (0)
124
125/**
126 * Acquires the TM lock and HDA lock, returns on failure.
127 */
128#define DEVHDA_LOCK_BOTH_RETURN(a_pDevIns, a_pThis, a_pStream, a_rcBusy) \
129 do { \
130 VBOXSTRICTRC rcLock = PDMDevHlpTimerLockClock2(pDevIns, (a_pStream)->hTimer, &(a_pThis)->CritSect, (a_rcBusy)); \
131 if (RT_LIKELY(rcLock == VINF_SUCCESS)) \
132 { /* likely */ } \
133 else \
134 return VBOXSTRICTRC_TODO(rcLock); \
135 } while (0)
136
137
138/*********************************************************************************************************************************
139* Structures and Typedefs *
140*********************************************************************************************************************************/
141
142/**
143 * Structure defining a (host backend) driver stream.
144 * Each driver has its own instances of audio mixer streams, which then
145 * can go into the same (or even different) audio mixer sinks.
146 */
147typedef struct HDADRIVERSTREAM
148{
149 /** Associated mixer handle. */
150 R3PTRTYPE(PAUDMIXSTREAM) pMixStrm;
151} HDADRIVERSTREAM, *PHDADRIVERSTREAM;
152
153/**
154 * Struct for maintaining a host backend driver.
155 * This driver must be associated to one, and only one,
156 * HDA codec. The HDA controller does the actual multiplexing
157 * of HDA codec data to various host backend drivers then.
158 *
159 * This HDA device uses a timer in order to synchronize all
160 * read/write accesses across all attached LUNs / backends.
161 */
162typedef struct HDADRIVER
163{
164 /** Node for storing this driver in our device driver list of HDASTATE. */
165 RTLISTNODER3 Node;
166 /** Pointer to shared HDA device state. */
167 R3PTRTYPE(PHDASTATE) pHDAStateShared;
168 /** Pointer to the ring-3 HDA device state. */
169 R3PTRTYPE(PHDASTATER3) pHDAStateR3;
170 /** LUN to which this driver has been assigned. */
171 uint8_t uLUN;
172 /** Whether this driver is in an attached state or not. */
173 bool fAttached;
174 uint8_t u32Padding0[6];
175 /** Pointer to attached driver base interface. */
176 R3PTRTYPE(PPDMIBASE) pDrvBase;
177 /** Audio connector interface to the underlying host backend. */
178 R3PTRTYPE(PPDMIAUDIOCONNECTOR) pConnector;
179 /** Mixer stream for line input. */
180 HDADRIVERSTREAM LineIn;
181#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
182 /** Mixer stream for mic input. */
183 HDADRIVERSTREAM MicIn;
184#endif
185 /** Mixer stream for front output. */
186 HDADRIVERSTREAM Front;
187#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
188 /** Mixer stream for center/LFE output. */
189 HDADRIVERSTREAM CenterLFE;
190 /** Mixer stream for rear output. */
191 HDADRIVERSTREAM Rear;
192#endif
193} HDADRIVER;
194/** The HDA host driver backend. */
195typedef struct HDADRIVER *PHDADRIVER;
196
197
198/** Internal state of this BDLE.
199 * Not part of the actual BDLE registers.
200 * @note Only for saved state. */
201typedef struct HDABDLESTATELEGACY
202{
203 /** Own index within the BDL (Buffer Descriptor List). */
204 uint32_t u32BDLIndex;
205 /** Number of bytes below the stream's FIFO watermark (SDFIFOW).
206 * Used to check if we need fill up the FIFO again. */
207 uint32_t cbBelowFIFOW;
208 /** Current offset in DMA buffer (in bytes).*/
209 uint32_t u32BufOff;
210 uint32_t Padding;
211} HDABDLESTATELEGACY;
212
213/**
214 * BDLE and state.
215 * @note Only for saved state.
216 */
217typedef struct HDABDLELEGACY
218{
219 /** The actual BDL description. */
220 HDABDLEDESC Desc;
221 HDABDLESTATELEGACY State;
222} HDABDLELEGACY;
223AssertCompileSize(HDABDLELEGACY, 32);
224
225
226/** Read callback. */
227typedef VBOXSTRICTRC FNHDAREGREAD(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
228/** Write callback. */
229typedef VBOXSTRICTRC FNHDAREGWRITE(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
230
231/**
232 * HDA register descriptor.
233 */
234typedef struct HDAREGDESC
235{
236 /** Register offset in the register space. */
237 uint32_t off;
238 /** Size in bytes. Registers of size > 4 are in fact tables. */
239 uint8_t cb;
240 /** Register descriptor (RD) flags of type HDA_RD_F_XXX. These are used to
241 * specify the read/write handling policy of the register. */
242 uint8_t fFlags;
243 /** Index into the register storage array (HDASTATE::au32Regs). */
244 uint8_t idxReg;
245 uint8_t bUnused;
246 /** Readable bits. */
247 uint32_t fReadableMask;
248 /** Writable bits. */
249 uint32_t fWritableMask;
250 /** Read callback. */
251 FNHDAREGREAD *pfnRead;
252 /** Write callback. */
253 FNHDAREGWRITE *pfnWrite;
254#if defined(IN_RING3) || defined(LOG_ENABLED) /* Saves 0x2f23 - 0x1888 = 0x169B (5787) bytes in VBoxDDR0. */
255 /** Abbreviated name. */
256 const char *pszName;
257# ifdef IN_RING3
258 /** Description (for stats). */
259 const char *pszDesc;
260# endif
261#endif
262} HDAREGDESC;
263
264
265/*********************************************************************************************************************************
266* Internal Functions *
267*********************************************************************************************************************************/
268#ifndef VBOX_DEVICE_STRUCT_TESTCASE
269#ifdef IN_RING3
270static void hdaR3GCTLReset(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC);
271#endif
272
273/** @name Register read/write stubs.
274 * @{
275 */
276static FNHDAREGREAD hdaRegReadUnimpl;
277static FNHDAREGWRITE hdaRegWriteUnimpl;
278/** @} */
279
280/** @name Global register set read/write functions.
281 * @{
282 */
283static FNHDAREGWRITE hdaRegWriteGCTL;
284static FNHDAREGREAD hdaRegReadLPIB;
285static FNHDAREGREAD hdaRegReadWALCLK;
286static FNHDAREGWRITE hdaRegWriteSSYNC;
287static FNHDAREGWRITE hdaRegWriteCORBWP;
288static FNHDAREGWRITE hdaRegWriteCORBRP;
289static FNHDAREGWRITE hdaRegWriteCORBCTL;
290static FNHDAREGWRITE hdaRegWriteCORBSIZE;
291static FNHDAREGWRITE hdaRegWriteCORBSTS;
292static FNHDAREGWRITE hdaRegWriteRINTCNT;
293static FNHDAREGWRITE hdaRegWriteRIRBWP;
294static FNHDAREGWRITE hdaRegWriteRIRBSTS;
295static FNHDAREGWRITE hdaRegWriteSTATESTS;
296static FNHDAREGWRITE hdaRegWriteIRS;
297static FNHDAREGREAD hdaRegReadIRS;
298static FNHDAREGWRITE hdaRegWriteBase;
299/** @} */
300
301/** @name {IOB}SDn write functions.
302 * @{
303 */
304static FNHDAREGWRITE hdaRegWriteSDCBL;
305static FNHDAREGWRITE hdaRegWriteSDCTL;
306static FNHDAREGWRITE hdaRegWriteSDSTS;
307static FNHDAREGWRITE hdaRegWriteSDLVI;
308static FNHDAREGWRITE hdaRegWriteSDFIFOW;
309static FNHDAREGWRITE hdaRegWriteSDFIFOS;
310static FNHDAREGWRITE hdaRegWriteSDFMT;
311static FNHDAREGWRITE hdaRegWriteSDBDPL;
312static FNHDAREGWRITE hdaRegWriteSDBDPU;
313/** @} */
314
315/** @name Generic register read/write functions.
316 * @{
317 */
318static FNHDAREGREAD hdaRegReadU32;
319static FNHDAREGWRITE hdaRegWriteU32;
320static FNHDAREGREAD hdaRegReadU24;
321#ifdef IN_RING3
322static FNHDAREGWRITE hdaRegWriteU24;
323#endif
324static FNHDAREGREAD hdaRegReadU16;
325static FNHDAREGWRITE hdaRegWriteU16;
326static FNHDAREGREAD hdaRegReadU8;
327static FNHDAREGWRITE hdaRegWriteU8;
328/** @} */
329
330/** @name HDA device functions.
331 * @{
332 */
333#ifdef IN_RING3
334static int hdaR3AddStream(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg);
335static int hdaR3RemoveStream(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg);
336#endif /* IN_RING3 */
337/** @} */
338
339/** @name HDA mixer functions.
340 * @{
341 */
342#ifdef IN_RING3
343static int hdaR3MixerAddDrvStream(PPDMDEVINS pDevIns, PAUDMIXSINK pMixSink, PCPDMAUDIOSTREAMCFG pCfg, PHDADRIVER pDrv);
344#endif
345/** @} */
346
347#ifdef IN_RING3
348static FNSSMFIELDGETPUT hdaR3GetPutTrans_HDABDLEDESC_fFlags_6;
349static FNSSMFIELDGETPUT hdaR3GetPutTrans_HDABDLE_Desc_fFlags_1thru4;
350#endif
351
352
353/*********************************************************************************************************************************
354* Global Variables *
355*********************************************************************************************************************************/
356/** No register description (RD) flags defined. */
357#define HDA_RD_F_NONE 0
358/** Writes to SD are allowed while RUN bit is set. */
359#define HDA_RD_F_SD_WRITE_RUN RT_BIT(0)
360
361/** @def HDA_REG_ENTRY_EX
362 * Maps the entry values to the actual HDAREGDESC layout, which is differs
363 * depending on context and build type. */
364#if defined(IN_RING3) || defined(LOG_ENABLED)
365# ifdef IN_RING3
366# define HDA_REG_ENTRY_EX(a_offBar, a_cbReg, a_fReadMask, a_fWriteMask, a_fFlags, a_pfnRead, a_pfnWrite, a_idxMap, a_szName, a_szDesc) \
367 { a_offBar, a_cbReg, a_fFlags, a_idxMap, 0, a_fReadMask, a_fWriteMask, a_pfnRead, a_pfnWrite, a_szName, a_szDesc }
368# else
369# define HDA_REG_ENTRY_EX(a_offBar, a_cbReg, a_fReadMask, a_fWriteMask, a_fFlags, a_pfnRead, a_pfnWrite, a_idxMap, a_szName, a_szDesc) \
370 { a_offBar, a_cbReg, a_fFlags, a_idxMap, 0, a_fReadMask, a_fWriteMask, a_pfnRead, a_pfnWrite, a_szName }
371# endif
372#else
373# define HDA_REG_ENTRY_EX(a_offBar, a_cbReg, a_fReadMask, a_fWriteMask, a_fFlags, a_pfnRead, a_pfnWrite, a_idxMap, a_szName, a_szDesc) \
374 { a_offBar, a_cbReg, a_fFlags, a_idxMap, 0, a_fReadMask, a_fWriteMask, a_pfnRead, a_pfnWrite }
375#endif
376
377#define HDA_REG_ENTRY(a_offBar, a_cbReg, a_fReadMask, a_fWriteMask, a_fFlags, a_pfnRead, a_pfnWrite, a_ShortRegNm, a_szDesc) \
378 HDA_REG_ENTRY_EX(a_offBar, a_cbReg, a_fReadMask, a_fWriteMask, a_fFlags, a_pfnRead, a_pfnWrite, HDA_MEM_IND_NAME(a_ShortRegNm), #a_ShortRegNm, a_szDesc)
379#define HDA_REG_ENTRY_STR(a_offBar, a_cbReg, a_fReadMask, a_fWriteMask, a_fFlags, a_pfnRead, a_pfnWrite, a_StrPrefix, a_ShortRegNm, a_szDesc) \
380 HDA_REG_ENTRY_EX(a_offBar, a_cbReg, a_fReadMask, a_fWriteMask, a_fFlags, a_pfnRead, a_pfnWrite, HDA_MEM_IND_NAME(a_StrPrefix ## a_ShortRegNm), #a_StrPrefix #a_ShortRegNm, #a_StrPrefix ": " a_szDesc)
381
382/** Emits a single audio stream register set (e.g. OSD0) at a specified offset. */
383#define HDA_REG_MAP_STRM(offset, name) \
384 /* offset size read mask write mask flags read callback write callback index, abbrev, description */ \
385 /* ------- ------- ---------- ---------- ---------------------- -------------- ----------------- ----------------------------- ----------- */ \
386 /* Offset 0x80 (SD0) */ \
387 HDA_REG_ENTRY_STR(offset, 0x00003, 0x00FF001F, 0x00F0001F, HDA_RD_F_SD_WRITE_RUN, hdaRegReadU24 , hdaRegWriteSDCTL , name, CTL , "Stream Descriptor Control"), \
388 /* Offset 0x83 (SD0) */ \
389 HDA_REG_ENTRY_STR(offset + 0x3, 0x00001, 0x0000003C, 0x0000001C, HDA_RD_F_SD_WRITE_RUN, hdaRegReadU8 , hdaRegWriteSDSTS , name, STS , "Status" ), \
390 /* Offset 0x84 (SD0) */ \
391 HDA_REG_ENTRY_STR(offset + 0x4, 0x00004, 0xFFFFFFFF, 0x00000000, HDA_RD_F_NONE, hdaRegReadLPIB, hdaRegWriteU32 , name, LPIB , "Link Position In Buffer" ), \
392 /* Offset 0x88 (SD0) */ \
393 HDA_REG_ENTRY_STR(offset + 0x8, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteSDCBL , name, CBL , "Cyclic Buffer Length" ), \
394 /* Offset 0x8C (SD0) -- upper 8 bits are reserved */ \
395 HDA_REG_ENTRY_STR(offset + 0xC, 0x00002, 0x0000FFFF, 0x000000FF, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteSDLVI , name, LVI , "Last Valid Index" ), \
396 /* Reserved: FIFO Watermark. ** @todo Document this! */ \
397 HDA_REG_ENTRY_STR(offset + 0xE, 0x00002, 0x00000007, 0x00000007, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteSDFIFOW, name, FIFOW, "FIFO Watermark" ), \
398 /* Offset 0x90 (SD0) */ \
399 HDA_REG_ENTRY_STR(offset + 0x10, 0x00002, 0x000000FF, 0x000000FF, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteSDFIFOS, name, FIFOS, "FIFO Size" ), \
400 /* Offset 0x92 (SD0) */ \
401 HDA_REG_ENTRY_STR(offset + 0x12, 0x00002, 0x00007F7F, 0x00007F7F, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteSDFMT , name, FMT , "Stream Format" ), \
402 /* Reserved: 0x94 - 0x98. */ \
403 /* Offset 0x98 (SD0) */ \
404 HDA_REG_ENTRY_STR(offset + 0x18, 0x00004, 0xFFFFFF80, 0xFFFFFF80, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteSDBDPL , name, BDPL , "Buffer Descriptor List Pointer-Lower Base Address" ), \
405 /* Offset 0x9C (SD0) */ \
406 HDA_REG_ENTRY_STR(offset + 0x1C, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteSDBDPU , name, BDPU , "Buffer Descriptor List Pointer-Upper Base Address" )
407
408/** Defines a single audio stream register set (e.g. OSD0). */
409#define HDA_REG_MAP_DEF_STREAM(index, name) \
410 HDA_REG_MAP_STRM(HDA_REG_DESC_SD0_BASE + (index * 32 /* 0x20 */), name)
411
412/** See 302349 p 6.2. */
413static const HDAREGDESC g_aHdaRegMap[HDA_NUM_REGS] =
414{
415 /* offset size read mask write mask flags read callback write callback index + abbrev */
416 /*------- ------- ---------- ---------- -------------- ---------------- ------------------- ------------------------ */
417 HDA_REG_ENTRY(0x00000, 0x00002, 0x0000FFFB, 0x00000000, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteUnimpl , GCAP, "Global Capabilities" ),
418 HDA_REG_ENTRY(0x00002, 0x00001, 0x000000FF, 0x00000000, HDA_RD_F_NONE, hdaRegReadU8 , hdaRegWriteUnimpl , VMIN, "Minor Version" ),
419 HDA_REG_ENTRY(0x00003, 0x00001, 0x000000FF, 0x00000000, HDA_RD_F_NONE, hdaRegReadU8 , hdaRegWriteUnimpl , VMAJ, "Major Version" ),
420 HDA_REG_ENTRY(0x00004, 0x00002, 0x0000FFFF, 0x00000000, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteU16 , OUTPAY, "Output Payload Capabilities" ),
421 HDA_REG_ENTRY(0x00006, 0x00002, 0x0000FFFF, 0x00000000, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteUnimpl , INPAY, "Input Payload Capabilities" ),
422 HDA_REG_ENTRY(0x00008, 0x00004, 0x00000103, 0x00000103, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteGCTL , GCTL, "Global Control" ),
423 HDA_REG_ENTRY(0x0000c, 0x00002, 0x00007FFF, 0x00007FFF, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteU16 , WAKEEN, "Wake Enable" ),
424 HDA_REG_ENTRY(0x0000e, 0x00002, 0x00000007, 0x00000007, HDA_RD_F_NONE, hdaRegReadU8 , hdaRegWriteSTATESTS, STATESTS, "State Change Status" ),
425 HDA_REG_ENTRY(0x00010, 0x00002, 0xFFFFFFFF, 0x00000000, HDA_RD_F_NONE, hdaRegReadUnimpl, hdaRegWriteUnimpl , GSTS, "Global Status" ),
426 HDA_REG_ENTRY(0x00018, 0x00002, 0x0000FFFF, 0x00000000, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteU16 , OUTSTRMPAY, "Output Stream Payload Capability" ),
427 HDA_REG_ENTRY(0x0001A, 0x00002, 0x0000FFFF, 0x00000000, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteUnimpl , INSTRMPAY, "Input Stream Payload Capability" ),
428 HDA_REG_ENTRY(0x00020, 0x00004, 0xC00000FF, 0xC00000FF, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteU32 , INTCTL, "Interrupt Control" ),
429 HDA_REG_ENTRY(0x00024, 0x00004, 0xC00000FF, 0x00000000, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteUnimpl , INTSTS, "Interrupt Status" ),
430 HDA_REG_ENTRY_EX(0x00030, 0x00004, 0xFFFFFFFF, 0x00000000, HDA_RD_F_NONE, hdaRegReadWALCLK, hdaRegWriteUnimpl , 0, "WALCLK", "Wall Clock Counter" ),
431 HDA_REG_ENTRY(0x00034, 0x00004, 0x000000FF, 0x000000FF, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteSSYNC , SSYNC, "Stream Synchronization" ),
432 HDA_REG_ENTRY(0x00040, 0x00004, 0xFFFFFF80, 0xFFFFFF80, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteBase , CORBLBASE, "CORB Lower Base Address" ),
433 HDA_REG_ENTRY(0x00044, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteBase , CORBUBASE, "CORB Upper Base Address" ),
434 HDA_REG_ENTRY(0x00048, 0x00002, 0x000000FF, 0x000000FF, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteCORBWP , CORBWP, "CORB Write Pointer" ),
435 HDA_REG_ENTRY(0x0004A, 0x00002, 0x000080FF, 0x00008000, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteCORBRP , CORBRP, "CORB Read Pointer" ),
436 HDA_REG_ENTRY(0x0004C, 0x00001, 0x00000003, 0x00000003, HDA_RD_F_NONE, hdaRegReadU8 , hdaRegWriteCORBCTL , CORBCTL, "CORB Control" ),
437 HDA_REG_ENTRY(0x0004D, 0x00001, 0x00000001, 0x00000001, HDA_RD_F_NONE, hdaRegReadU8 , hdaRegWriteCORBSTS , CORBSTS, "CORB Status" ),
438 HDA_REG_ENTRY(0x0004E, 0x00001, 0x000000F3, 0x00000003, HDA_RD_F_NONE, hdaRegReadU8 , hdaRegWriteCORBSIZE, CORBSIZE, "CORB Size" ),
439 HDA_REG_ENTRY(0x00050, 0x00004, 0xFFFFFF80, 0xFFFFFF80, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteBase , RIRBLBASE, "RIRB Lower Base Address" ),
440 HDA_REG_ENTRY(0x00054, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteBase , RIRBUBASE, "RIRB Upper Base Address" ),
441 HDA_REG_ENTRY(0x00058, 0x00002, 0x000000FF, 0x00008000, HDA_RD_F_NONE, hdaRegReadU8 , hdaRegWriteRIRBWP , RIRBWP, "RIRB Write Pointer" ),
442 HDA_REG_ENTRY(0x0005A, 0x00002, 0x000000FF, 0x000000FF, HDA_RD_F_NONE, hdaRegReadU16 , hdaRegWriteRINTCNT , RINTCNT, "Response Interrupt Count" ),
443 HDA_REG_ENTRY(0x0005C, 0x00001, 0x00000007, 0x00000007, HDA_RD_F_NONE, hdaRegReadU8 , hdaRegWriteU8 , RIRBCTL, "RIRB Control" ),
444 HDA_REG_ENTRY(0x0005D, 0x00001, 0x00000005, 0x00000005, HDA_RD_F_NONE, hdaRegReadU8 , hdaRegWriteRIRBSTS , RIRBSTS, "RIRB Status" ),
445 HDA_REG_ENTRY(0x0005E, 0x00001, 0x000000F3, 0x00000000, HDA_RD_F_NONE, hdaRegReadU8 , hdaRegWriteUnimpl , RIRBSIZE, "RIRB Size" ),
446 HDA_REG_ENTRY(0x00060, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteU32 , IC, "Immediate Command" ),
447 HDA_REG_ENTRY(0x00064, 0x00004, 0x00000000, 0xFFFFFFFF, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteUnimpl , IR, "Immediate Response" ),
448 HDA_REG_ENTRY(0x00068, 0x00002, 0x00000002, 0x00000002, HDA_RD_F_NONE, hdaRegReadIRS , hdaRegWriteIRS , IRS, "Immediate Command Status" ),
449 HDA_REG_ENTRY(0x00070, 0x00004, 0xFFFFFFFF, 0xFFFFFF81, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteBase , DPLBASE, "DMA Position Lower Base" ),
450 HDA_REG_ENTRY(0x00074, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, HDA_RD_F_NONE, hdaRegReadU32 , hdaRegWriteBase , DPUBASE, "DMA Position Upper Base" ),
451 /* 4 Serial Data In (SDI). */
452 HDA_REG_MAP_DEF_STREAM(0, SD0),
453 HDA_REG_MAP_DEF_STREAM(1, SD1),
454 HDA_REG_MAP_DEF_STREAM(2, SD2),
455 HDA_REG_MAP_DEF_STREAM(3, SD3),
456 /* 4 Serial Data Out (SDO). */
457 HDA_REG_MAP_DEF_STREAM(4, SD4),
458 HDA_REG_MAP_DEF_STREAM(5, SD5),
459 HDA_REG_MAP_DEF_STREAM(6, SD6),
460 HDA_REG_MAP_DEF_STREAM(7, SD7)
461};
462
463#undef HDA_REG_ENTRY_EX
464#undef HDA_REG_ENTRY
465#undef HDA_REG_ENTRY_STR
466#undef HDA_REG_MAP_STRM
467#undef HDA_REG_MAP_DEF_STREAM
468
469/**
470 * HDA register aliases (HDA spec 3.3.45).
471 * @remarks Sorted by offReg.
472 */
473static struct HDAREGALIAS
474{
475 /** The alias register offset. */
476 uint32_t offReg;
477 /** The register index. */
478 int idxAlias;
479} const g_aHdaRegAliases[] =
480{
481 { 0x2030, HDA_REG_WALCLK },
482 { 0x2084, HDA_REG_SD0LPIB },
483 { 0x20a4, HDA_REG_SD1LPIB },
484 { 0x20c4, HDA_REG_SD2LPIB },
485 { 0x20e4, HDA_REG_SD3LPIB },
486 { 0x2104, HDA_REG_SD4LPIB },
487 { 0x2124, HDA_REG_SD5LPIB },
488 { 0x2144, HDA_REG_SD6LPIB },
489 { 0x2164, HDA_REG_SD7LPIB }
490};
491
492#ifdef IN_RING3
493
494/** HDABDLEDESC field descriptors for the v7+ saved state. */
495static SSMFIELD const g_aSSMBDLEDescFields7[] =
496{
497 SSMFIELD_ENTRY(HDABDLEDESC, u64BufAddr),
498 SSMFIELD_ENTRY(HDABDLEDESC, u32BufSize),
499 SSMFIELD_ENTRY(HDABDLEDESC, fFlags),
500 SSMFIELD_ENTRY_TERM()
501};
502
503/** HDABDLEDESC field descriptors for the v6 saved states. */
504static SSMFIELD const g_aSSMBDLEDescFields6[] =
505{
506 SSMFIELD_ENTRY(HDABDLEDESC, u64BufAddr),
507 SSMFIELD_ENTRY(HDABDLEDESC, u32BufSize),
508 SSMFIELD_ENTRY_CALLBACK(HDABDLEDESC, fFlags, hdaR3GetPutTrans_HDABDLEDESC_fFlags_6),
509 SSMFIELD_ENTRY_TERM()
510};
511
512/** HDABDLESTATE field descriptors for the v6 saved state. */
513static SSMFIELD const g_aSSMBDLEStateFields6[] =
514{
515 SSMFIELD_ENTRY(HDABDLESTATELEGACY, u32BDLIndex),
516 SSMFIELD_ENTRY(HDABDLESTATELEGACY, cbBelowFIFOW),
517 SSMFIELD_ENTRY_OLD(FIFO, 256), /* Deprecated; now is handled in the stream's circular buffer. */
518 SSMFIELD_ENTRY(HDABDLESTATELEGACY, u32BufOff),
519 SSMFIELD_ENTRY_TERM()
520};
521
522/** HDABDLESTATE field descriptors for the v7+ saved state. */
523static SSMFIELD const g_aSSMBDLEStateFields7[] =
524{
525 SSMFIELD_ENTRY(HDABDLESTATELEGACY, u32BDLIndex),
526 SSMFIELD_ENTRY(HDABDLESTATELEGACY, cbBelowFIFOW),
527 SSMFIELD_ENTRY(HDABDLESTATELEGACY, u32BufOff),
528 SSMFIELD_ENTRY_TERM()
529};
530
531/** HDASTREAMSTATE field descriptors for the v6 saved state. */
532static SSMFIELD const g_aSSMStreamStateFields6[] =
533{
534 SSMFIELD_ENTRY_OLD(cBDLE, sizeof(uint16_t)), /* Deprecated. */
535 SSMFIELD_ENTRY_OLD(uCurBDLE, sizeof(uint16_t)), /* We figure it out from LPID */
536 SSMFIELD_ENTRY_OLD(fStop, 1), /* Deprecated; see SSMR3PutBool(). */
537 SSMFIELD_ENTRY_OLD(fRunning, 1), /* Deprecated; using the HDA_SDCTL_RUN bit is sufficient. */
538 SSMFIELD_ENTRY(HDASTREAMSTATE, fInReset),
539 SSMFIELD_ENTRY_TERM()
540};
541
542/** HDASTREAMSTATE field descriptors for the v7+ saved state. */
543static SSMFIELD const g_aSSMStreamStateFields7[] =
544{
545 SSMFIELD_ENTRY(HDASTREAMSTATE, idxCurBdle), /* For backward compatibility we save this. We use LPIB on restore. */
546 SSMFIELD_ENTRY_OLD(uCurBDLEHi, sizeof(uint8_t)), /* uCurBDLE was 16-bit for some reason, so store/ignore the zero top byte. */
547 SSMFIELD_ENTRY(HDASTREAMSTATE, fInReset),
548 SSMFIELD_ENTRY(HDASTREAMSTATE, tsTransferNext),
549 SSMFIELD_ENTRY_TERM()
550};
551
552/** HDABDLE field descriptors for the v1 thru v4 saved states. */
553static SSMFIELD const g_aSSMStreamBdleFields1234[] =
554{
555 SSMFIELD_ENTRY(HDABDLELEGACY, Desc.u64BufAddr), /* u64BdleCviAddr */
556 SSMFIELD_ENTRY_OLD(u32BdleMaxCvi, sizeof(uint32_t)), /* u32BdleMaxCvi */
557 SSMFIELD_ENTRY(HDABDLELEGACY, State.u32BDLIndex), /* u32BdleCvi */
558 SSMFIELD_ENTRY(HDABDLELEGACY, Desc.u32BufSize), /* u32BdleCviLen */
559 SSMFIELD_ENTRY(HDABDLELEGACY, State.u32BufOff), /* u32BdleCviPos */
560 SSMFIELD_ENTRY_CALLBACK(HDABDLELEGACY, Desc.fFlags, hdaR3GetPutTrans_HDABDLE_Desc_fFlags_1thru4), /* fBdleCviIoc */
561 SSMFIELD_ENTRY(HDABDLELEGACY, State.cbBelowFIFOW), /* cbUnderFifoW */
562 SSMFIELD_ENTRY_OLD(au8FIFO, 256), /* au8FIFO */
563 SSMFIELD_ENTRY_TERM()
564};
565
566#endif /* IN_RING3 */
567
568/**
569 * 32-bit size indexed masks, i.e. g_afMasks[2 bytes] = 0xffff.
570 */
571static uint32_t const g_afMasks[5] =
572{
573 UINT32_C(0), UINT32_C(0x000000ff), UINT32_C(0x0000ffff), UINT32_C(0x00ffffff), UINT32_C(0xffffffff)
574};
575
576
577#ifdef VBOX_STRICT
578
579/**
580 * Strict register accessor verifing defines and mapping table.
581 * @see HDA_REG
582 */
583DECLINLINE(uint32_t *) hdaStrictRegAccessor(PHDASTATE pThis, uint32_t idxMap, uint32_t idxReg)
584{
585 Assert(idxMap < RT_ELEMENTS(g_aHdaRegMap));
586 AssertMsg(idxReg == g_aHdaRegMap[idxMap].idxReg, ("idxReg=%d\n", idxReg));
587 return &pThis->au32Regs[idxReg];
588}
589
590/**
591 * Strict stream register accessor verifing defines and mapping table.
592 * @see HDA_STREAM_REG
593 */
594DECLINLINE(uint32_t *) hdaStrictStreamRegAccessor(PHDASTATE pThis, uint32_t idxMap0, uint32_t idxReg0, size_t idxStream)
595{
596 Assert(idxMap0 < RT_ELEMENTS(g_aHdaRegMap));
597 AssertMsg(idxStream < RT_ELEMENTS(pThis->aStreams), ("%#zx\n", idxStream));
598 AssertMsg(idxReg0 + idxStream * 10 == g_aHdaRegMap[idxMap0 + idxStream * 10].idxReg,
599 ("idxReg0=%d idxStream=%zx\n", idxReg0, idxStream));
600 return &pThis->au32Regs[idxReg0 + idxStream * 10];
601}
602
603#endif /* VBOX_STRICT */
604
605
606/**
607 * Returns a new INTSTS value based on the current device state.
608 *
609 * @returns Determined INTSTS register value.
610 * @param pThis The shared HDA device state.
611 *
612 * @remarks This function does *not* set INTSTS!
613 */
614static uint32_t hdaGetINTSTS(PHDASTATE pThis)
615{
616 uint32_t intSts = 0;
617
618 /* Check controller interrupts (RIRB, STATEST). */
619 if (HDA_REG(pThis, RIRBSTS) & HDA_REG(pThis, RIRBCTL) & (HDA_RIRBCTL_ROIC | HDA_RIRBCTL_RINTCTL))
620 {
621 intSts |= HDA_INTSTS_CIS; /* Set the Controller Interrupt Status (CIS). */
622 }
623
624 /* Check SDIN State Change Status Flags. */
625 if (HDA_REG(pThis, STATESTS) & HDA_REG(pThis, WAKEEN))
626 {
627 intSts |= HDA_INTSTS_CIS; /* Touch Controller Interrupt Status (CIS). */
628 }
629
630 /* For each stream, check if any interrupt status bit is set and enabled. */
631 for (uint8_t iStrm = 0; iStrm < HDA_MAX_STREAMS; ++iStrm)
632 {
633 if (HDA_STREAM_REG(pThis, STS, iStrm) & HDA_STREAM_REG(pThis, CTL, iStrm) & (HDA_SDCTL_DEIE | HDA_SDCTL_FEIE | HDA_SDCTL_IOCE))
634 {
635 Log3Func(("[SD%d] interrupt status set\n", iStrm));
636 intSts |= RT_BIT(iStrm);
637 }
638 }
639
640 if (intSts)
641 intSts |= HDA_INTSTS_GIS; /* Set the Global Interrupt Status (GIS). */
642
643 Log3Func(("-> 0x%x\n", intSts));
644
645 return intSts;
646}
647
648
649/**
650 * Processes (asserts/deasserts) the HDA interrupt according to the current state.
651 *
652 * @param pDevIns The device instance.
653 * @param pThis The shared HDA device state.
654 * @param pszSource Caller information.
655 */
656#if defined(LOG_ENABLED) || defined(DOXYGEN_RUNNING)
657void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis, const char *pszSource)
658#else
659void hdaProcessInterrupt(PPDMDEVINS pDevIns, PHDASTATE pThis)
660#endif
661{
662 uint32_t uIntSts = hdaGetINTSTS(pThis);
663
664 HDA_REG(pThis, INTSTS) = uIntSts;
665
666 /* NB: It is possible to have GIS set even when CIE/SIEn are all zero; the GIS bit does
667 * not control the interrupt signal. See Figure 4 on page 54 of the HDA 1.0a spec.
668 */
669 /* Global Interrupt Enable (GIE) set? */
670 if ( (HDA_REG(pThis, INTCTL) & HDA_INTCTL_GIE)
671 && (HDA_REG(pThis, INTSTS) & HDA_REG(pThis, INTCTL) & (HDA_INTCTL_CIE | HDA_STRMINT_MASK)))
672 {
673 Log3Func(("Asserted (%s)\n", pszSource));
674
675 PDMDevHlpPCISetIrq(pDevIns, 0, 1 /* Assert */);
676 pThis->u8IRQL = 1;
677
678#ifdef DEBUG
679 pThis->Dbg.IRQ.tsAssertedNs = RTTimeNanoTS();
680 pThis->Dbg.IRQ.tsProcessedLastNs = pThis->Dbg.IRQ.tsAssertedNs;
681#endif
682 }
683 else
684 {
685 Log3Func(("Deasserted (%s)\n", pszSource));
686
687 PDMDevHlpPCISetIrq(pDevIns, 0, 0 /* Deassert */);
688 pThis->u8IRQL = 0;
689 }
690}
691
692
693/**
694 * Looks up a register at the exact offset given by @a offReg.
695 *
696 * @returns Register index on success, -1 if not found.
697 * @param offReg The register offset.
698 */
699static int hdaRegLookup(uint32_t offReg)
700{
701 /*
702 * Aliases.
703 */
704 if (offReg >= g_aHdaRegAliases[0].offReg)
705 {
706 for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegAliases); i++)
707 if (offReg == g_aHdaRegAliases[i].offReg)
708 return g_aHdaRegAliases[i].idxAlias;
709 Assert(g_aHdaRegMap[RT_ELEMENTS(g_aHdaRegMap) - 1].off < offReg);
710 return -1;
711 }
712
713 /*
714 * Binary search the
715 */
716 int idxEnd = RT_ELEMENTS(g_aHdaRegMap);
717 int idxLow = 0;
718 for (;;)
719 {
720 int idxMiddle = idxLow + (idxEnd - idxLow) / 2;
721 if (offReg < g_aHdaRegMap[idxMiddle].off)
722 {
723 if (idxLow == idxMiddle)
724 break;
725 idxEnd = idxMiddle;
726 }
727 else if (offReg > g_aHdaRegMap[idxMiddle].off)
728 {
729 idxLow = idxMiddle + 1;
730 if (idxLow >= idxEnd)
731 break;
732 }
733 else
734 return idxMiddle;
735 }
736
737#ifdef RT_STRICT
738 for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
739 Assert(g_aHdaRegMap[i].off != offReg);
740#endif
741 return -1;
742}
743
744#ifdef IN_RING3
745
746/**
747 * Looks up a register covering the offset given by @a offReg.
748 *
749 * @returns Register index on success, -1 if not found.
750 * @param offReg The register offset.
751 */
752static int hdaR3RegLookupWithin(uint32_t offReg)
753{
754 /*
755 * Aliases.
756 */
757 if (offReg >= g_aHdaRegAliases[0].offReg)
758 {
759 for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegAliases); i++)
760 {
761 uint32_t off = offReg - g_aHdaRegAliases[i].offReg;
762 if (off < 4 && off < g_aHdaRegMap[g_aHdaRegAliases[i].idxAlias].cb)
763 return g_aHdaRegAliases[i].idxAlias;
764 }
765 Assert(g_aHdaRegMap[RT_ELEMENTS(g_aHdaRegMap) - 1].off < offReg);
766 return -1;
767 }
768
769 /*
770 * Binary search the register map.
771 */
772 int idxEnd = RT_ELEMENTS(g_aHdaRegMap);
773 int idxLow = 0;
774 for (;;)
775 {
776 int idxMiddle = idxLow + (idxEnd - idxLow) / 2;
777 if (offReg < g_aHdaRegMap[idxMiddle].off)
778 {
779 if (idxLow == idxMiddle)
780 break;
781 idxEnd = idxMiddle;
782 }
783 else if (offReg >= g_aHdaRegMap[idxMiddle].off + g_aHdaRegMap[idxMiddle].cb)
784 {
785 idxLow = idxMiddle + 1;
786 if (idxLow >= idxEnd)
787 break;
788 }
789 else
790 return idxMiddle;
791 }
792
793# ifdef RT_STRICT
794 for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
795 Assert(offReg - g_aHdaRegMap[i].off >= g_aHdaRegMap[i].cb);
796# endif
797 return -1;
798}
799
800#endif /* IN_RING3 */
801
802#ifdef IN_RING3 /* Codec is not yet kosher enough for ring-0. @bugref{9890c64} */
803
804/**
805 * Synchronizes the CORB / RIRB buffers between internal <-> device state.
806 *
807 * @returns VBox status code.
808 *
809 * @param pDevIns The device instance.
810 * @param pThis The shared HDA device state.
811 * @param fLocal Specify true to synchronize HDA state's CORB buffer with the device state,
812 * or false to synchronize the device state's RIRB buffer with the HDA state.
813 *
814 * @todo r=andy Break this up into two functions?
815 */
816static int hdaR3CmdSync(PPDMDEVINS pDevIns, PHDASTATE pThis, bool fLocal)
817{
818 int rc = VINF_SUCCESS;
819 if (fLocal)
820 {
821 if (pThis->u64CORBBase)
822 {
823 Assert(pThis->cbCorbBuf);
824 rc = PDMDevHlpPCIPhysRead(pDevIns, pThis->u64CORBBase, pThis->au32CorbBuf,
825 RT_MIN(pThis->cbCorbBuf, sizeof(pThis->au32CorbBuf)));
826 Log3Func(("CORB: read %RGp LB %#x (%Rrc)\n", pThis->u64CORBBase, pThis->cbCorbBuf, rc));
827 AssertRCReturn(rc, rc);
828 }
829 }
830 else
831 {
832 if (pThis->u64RIRBBase)
833 {
834 Assert(pThis->cbRirbBuf);
835
836 rc = PDMDevHlpPCIPhysWrite(pDevIns, pThis->u64RIRBBase, pThis->au64RirbBuf,
837 RT_MIN(pThis->cbRirbBuf, sizeof(pThis->au64RirbBuf)));
838 Log3Func(("RIRB: phys read %RGp LB %#x (%Rrc)\n", pThis->u64RIRBBase, pThis->cbRirbBuf, rc));
839 AssertRCReturn(rc, rc);
840 }
841 }
842
843# ifdef DEBUG_CMD_BUFFER
844 LogFunc(("fLocal=%RTbool\n", fLocal));
845
846 uint8_t i = 0;
847 do
848 {
849 LogFunc(("CORB%02x: ", i));
850 uint8_t j = 0;
851 do
852 {
853 const char *pszPrefix;
854 if ((i + j) == HDA_REG(pThis, CORBRP))
855 pszPrefix = "[R]";
856 else if ((i + j) == HDA_REG(pThis, CORBWP))
857 pszPrefix = "[W]";
858 else
859 pszPrefix = " "; /* three spaces */
860 Log((" %s%08x", pszPrefix, pThis->pu32CorbBuf[i + j]));
861 j++;
862 } while (j < 8);
863 Log(("\n"));
864 i += 8;
865 } while (i != 0);
866
867 do
868 {
869 LogFunc(("RIRB%02x: ", i));
870 uint8_t j = 0;
871 do
872 {
873 const char *prefix;
874 if ((i + j) == HDA_REG(pThis, RIRBWP))
875 prefix = "[W]";
876 else
877 prefix = " ";
878 Log((" %s%016lx", prefix, pThis->pu64RirbBuf[i + j]));
879 } while (++j < 8);
880 Log(("\n"));
881 i += 8;
882 } while (i != 0);
883# endif
884 return rc;
885}
886
887
888/**
889 * Processes the next CORB buffer command in the queue.
890 *
891 * This will invoke the HDA codec ring-3 verb dispatcher.
892 *
893 * @returns VBox status code.
894 * @param pDevIns The device instance.
895 * @param pThis The shared HDA device state.
896 * @param pThisCC The ring-0 HDA device state.
897 */
898static int hdaR3CORBCmdProcess(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATECC pThisCC)
899{
900 Log3Func(("ENTER CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP), HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP)));
901
902 if (!(HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA))
903 {
904 LogFunc(("CORB DMA not active, skipping\n"));
905 return VINF_SUCCESS;
906 }
907
908 Assert(pThis->cbCorbBuf);
909
910 int rc = hdaR3CmdSync(pDevIns, pThis, true /* Sync from guest */);
911 AssertRCReturn(rc, rc);
912
913 /*
914 * Prepare local copies of relevant registers.
915 */
916 uint16_t cIntCnt = HDA_REG(pThis, RINTCNT) & 0xff;
917 if (!cIntCnt) /* 0 means 256 interrupts. */
918 cIntCnt = HDA_MAX_RINTCNT;
919
920 uint32_t const cCorbEntries = RT_MIN(RT_MAX(pThis->cbCorbBuf, 1), sizeof(pThis->au32CorbBuf)) / HDA_CORB_ELEMENT_SIZE;
921 uint8_t const corbWp = HDA_REG(pThis, CORBWP) % cCorbEntries;
922 uint8_t corbRp = HDA_REG(pThis, CORBRP);
923 uint8_t rirbWp = HDA_REG(pThis, RIRBWP);
924
925 /*
926 * The loop.
927 */
928 Log3Func(("START CORB(RP:%x, WP:%x) RIRBWP:%x, RINTCNT:%RU8/%RU8\n", corbRp, corbWp, rirbWp, pThis->u16RespIntCnt, cIntCnt));
929 while (corbRp != corbWp)
930 {
931 /* Fetch the command from the CORB. */
932 corbRp = (corbRp + 1) /* Advance +1 as the first command(s) are at CORBWP + 1. */ % cCorbEntries;
933 uint32_t const uCmd = pThis->au32CorbBuf[corbRp];
934
935 /*
936 * Execute the command.
937 */
938 uint64_t uResp = 0;
939 rc = pThisCC->Codec.pfnLookup(&pThisCC->Codec, HDA_CODEC_CMD(uCmd, 0 /* Codec index */), &uResp);
940 if (RT_SUCCESS(rc))
941 AssertRCSuccess(rc); /* no informational statuses */
942 else
943 Log3Func(("Lookup for codec verb %08x failed: %Rrc\n", uCmd, rc));
944 Log3Func(("Codec verb %08x -> response %016RX64\n", uCmd, uResp));
945
946 if ( (uResp & CODEC_RESPONSE_UNSOLICITED)
947 && !(HDA_REG(pThis, GCTL) & HDA_GCTL_UNSOL))
948 {
949 LogFunc(("Unexpected unsolicited response.\n"));
950 HDA_REG(pThis, CORBRP) = corbRp;
951 /** @todo r=andy No RIRB syncing to guest required in that case? */
952 /** @todo r=bird: Why isn't RIRBWP updated here. The response might come
953 * after already processing several commands, can't it? (When you think
954 * about it, it is bascially the same question as Andy is asking.) */
955 return VINF_SUCCESS;
956 }
957
958 /*
959 * Store the response in the RIRB.
960 */
961 AssertCompile(HDA_RIRB_SIZE == RT_ELEMENTS(pThis->au64RirbBuf));
962 rirbWp = (rirbWp + 1) % HDA_RIRB_SIZE;
963 pThis->au64RirbBuf[rirbWp] = uResp;
964
965 /*
966 * Send interrupt if needed.
967 */
968 bool fSendInterrupt = false;
969 pThis->u16RespIntCnt++;
970 if (pThis->u16RespIntCnt >= cIntCnt) /* Response interrupt count reached? */
971 {
972 pThis->u16RespIntCnt = 0; /* Reset internal interrupt response counter. */
973
974 Log3Func(("Response interrupt count reached (%RU16)\n", pThis->u16RespIntCnt));
975 fSendInterrupt = true;
976 }
977 else if (corbRp == corbWp) /* Did we reach the end of the current command buffer? */
978 {
979 Log3Func(("Command buffer empty\n"));
980 fSendInterrupt = true;
981 }
982 if (fSendInterrupt)
983 {
984 if (HDA_REG(pThis, RIRBCTL) & HDA_RIRBCTL_RINTCTL) /* Response Interrupt Control (RINTCTL) enabled? */
985 {
986 HDA_REG(pThis, RIRBSTS) |= HDA_RIRBSTS_RINTFL;
987 HDA_PROCESS_INTERRUPT(pDevIns, pThis);
988 }
989 }
990 }
991
992 /*
993 * Put register locals back.
994 */
995 Log3Func(("END CORB(RP:%x, WP:%x) RIRBWP:%x, RINTCNT:%RU8/%RU8\n", corbRp, corbWp, rirbWp, pThis->u16RespIntCnt, cIntCnt));
996 HDA_REG(pThis, CORBRP) = corbRp;
997 HDA_REG(pThis, RIRBWP) = rirbWp;
998
999 /*
1000 * Write out the response.
1001 */
1002 rc = hdaR3CmdSync(pDevIns, pThis, false /* Sync to guest */);
1003 AssertRC(rc);
1004
1005 return rc;
1006}
1007
1008#endif /* IN_RING3 - @bugref{9890c64} */
1009
1010#ifdef IN_RING3
1011/**
1012 * @callback_method_impl{FNPDMTASKDEV, Continue CORB DMA in ring-3}
1013 */
1014static DECLCALLBACK(void) hdaR3CorbDmaTaskWorker(PPDMDEVINS pDevIns, void *pvUser)
1015{
1016 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
1017 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
1018 RT_NOREF(pvUser);
1019 LogFlowFunc(("\n"));
1020
1021 DEVHDA_LOCK(pDevIns, pThis);
1022 hdaR3CORBCmdProcess(pDevIns, pThis, pThisCC);
1023 DEVHDA_UNLOCK(pDevIns, pThis);
1024
1025}
1026#endif /* IN_RING3 */
1027
1028/* Register access handlers. */
1029
1030static VBOXSTRICTRC hdaRegReadUnimpl(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
1031{
1032 RT_NOREF(pDevIns, pThis, iReg);
1033 *pu32Value = 0;
1034 return VINF_SUCCESS;
1035}
1036
1037static VBOXSTRICTRC hdaRegWriteUnimpl(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1038{
1039 RT_NOREF(pDevIns, pThis, iReg, u32Value);
1040 return VINF_SUCCESS;
1041}
1042
1043/* U8 */
1044static VBOXSTRICTRC hdaRegReadU8(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
1045{
1046 Assert(((pThis->au32Regs[g_aHdaRegMap[iReg].idxReg] & g_aHdaRegMap[iReg].fReadableMask) & UINT32_C(0xffffff00)) == 0);
1047 return hdaRegReadU32(pDevIns, pThis, iReg, pu32Value);
1048}
1049
1050static VBOXSTRICTRC hdaRegWriteU8(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1051{
1052 Assert((u32Value & 0xffffff00) == 0);
1053 return hdaRegWriteU32(pDevIns, pThis, iReg, u32Value);
1054}
1055
1056/* U16 */
1057static VBOXSTRICTRC hdaRegReadU16(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
1058{
1059 Assert(((pThis->au32Regs[g_aHdaRegMap[iReg].idxReg] & g_aHdaRegMap[iReg].fReadableMask) & UINT32_C(0xffff0000)) == 0);
1060 return hdaRegReadU32(pDevIns, pThis, iReg, pu32Value);
1061}
1062
1063static VBOXSTRICTRC hdaRegWriteU16(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1064{
1065 Assert((u32Value & 0xffff0000) == 0);
1066 return hdaRegWriteU32(pDevIns, pThis, iReg, u32Value);
1067}
1068
1069/* U24 */
1070static VBOXSTRICTRC hdaRegReadU24(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
1071{
1072 Assert(((pThis->au32Regs[g_aHdaRegMap[iReg].idxReg] & g_aHdaRegMap[iReg].fReadableMask) & UINT32_C(0xff000000)) == 0);
1073 return hdaRegReadU32(pDevIns, pThis, iReg, pu32Value);
1074}
1075
1076#ifdef IN_RING3
1077static VBOXSTRICTRC hdaRegWriteU24(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1078{
1079 Assert((u32Value & 0xff000000) == 0);
1080 return hdaRegWriteU32(pDevIns, pThis, iReg, u32Value);
1081}
1082#endif
1083
1084/* U32 */
1085static VBOXSTRICTRC hdaRegReadU32(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
1086{
1087 RT_NOREF(pDevIns);
1088
1089 uint32_t const iRegMem = g_aHdaRegMap[iReg].idxReg;
1090 *pu32Value = pThis->au32Regs[iRegMem] & g_aHdaRegMap[iReg].fReadableMask;
1091 return VINF_SUCCESS;
1092}
1093
1094static VBOXSTRICTRC hdaRegWriteU32(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1095{
1096 RT_NOREF(pDevIns);
1097
1098 uint32_t const iRegMem = g_aHdaRegMap[iReg].idxReg;
1099 pThis->au32Regs[iRegMem] = (u32Value & g_aHdaRegMap[iReg].fWritableMask)
1100 | (pThis->au32Regs[iRegMem] & ~g_aHdaRegMap[iReg].fWritableMask);
1101 return VINF_SUCCESS;
1102}
1103
1104static VBOXSTRICTRC hdaRegWriteGCTL(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1105{
1106 RT_NOREF(pDevIns, iReg);
1107
1108 if (u32Value & HDA_GCTL_CRST)
1109 {
1110 /* Set the CRST bit to indicate that we're leaving reset mode. */
1111 HDA_REG(pThis, GCTL) |= HDA_GCTL_CRST;
1112 LogFunc(("Guest leaving HDA reset\n"));
1113 }
1114 else
1115 {
1116#ifdef IN_RING3
1117 /* Enter reset state. */
1118 LogFunc(("Guest entering HDA reset with DMA(RIRB:%s, CORB:%s)\n",
1119 HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA ? "on" : "off",
1120 HDA_REG(pThis, RIRBCTL) & HDA_RIRBCTL_RDMAEN ? "on" : "off"));
1121
1122 /* Clear the CRST bit to indicate that we're in reset state. */
1123 HDA_REG(pThis, GCTL) &= ~HDA_GCTL_CRST;
1124
1125 hdaR3GCTLReset(pDevIns, pThis, PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3));
1126#else
1127 return VINF_IOM_R3_MMIO_WRITE;
1128#endif
1129 }
1130
1131 if (u32Value & HDA_GCTL_FCNTRL)
1132 {
1133 /* Flush: GSTS:1 set, see 6.2.6. */
1134 HDA_REG(pThis, GSTS) |= HDA_GSTS_FSTS; /* Set the flush status. */
1135 /* DPLBASE and DPUBASE should be initialized with initial value (see 6.2.6). */
1136 }
1137
1138 return VINF_SUCCESS;
1139}
1140
1141static VBOXSTRICTRC hdaRegWriteSTATESTS(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1142{
1143 RT_NOREF(pDevIns);
1144
1145 uint32_t v = HDA_REG_IND(pThis, iReg);
1146 uint32_t nv = u32Value & HDA_STATESTS_SCSF_MASK;
1147
1148 HDA_REG(pThis, STATESTS) &= ~(v & nv); /* Write of 1 clears corresponding bit. */
1149
1150 return VINF_SUCCESS;
1151}
1152
1153static VBOXSTRICTRC hdaRegReadLPIB(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
1154{
1155 RT_NOREF(pDevIns);
1156 uint8_t const uSD = HDA_SD_NUM_FROM_REG(pThis, LPIB, iReg);
1157 uint32_t const uLPIB = HDA_STREAM_REG(pThis, LPIB, uSD);
1158
1159#ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
1160 /*
1161 * Should we consider doing DMA work while we're here? That would require
1162 * the stream to have the DMA engine enabled and be an output stream.
1163 */
1164 if ( (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_RUN)
1165 && hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT
1166 && uSD < RT_ELEMENTS(pThis->aStreams) /* paranoia */)
1167 {
1168 PHDASTREAM const pStreamShared = &pThis->aStreams[uSD];
1169 Assert(pStreamShared->u8SD == uSD);
1170 if (pStreamShared->State.fRunning /* should be same as HDA_SDCTL_RUN, but doesn't hurt to check twice */)
1171 {
1172 /*
1173 * Calculate where the DMA engine should be according to the clock, if we can.
1174 */
1175 uint32_t const cbFrame = PDMAudioPropsFrameSize(&pStreamShared->State.Cfg.Props);
1176 uint32_t const cbPeriod = pStreamShared->State.cbCurDmaPeriod;
1177 if (cbPeriod > cbFrame)
1178 {
1179 AssertMsg(pStreamShared->State.cbDmaTotal < cbPeriod, ("%#x vs %#x\n", pStreamShared->State.cbDmaTotal, cbPeriod));
1180 uint64_t const tsTransferNext = pStreamShared->State.tsTransferNext;
1181 uint64_t const tsNow = PDMDevHlpTimerGet(pDevIns, pThis->aStreams[0].hTimer); /* only #0 works in r0 */
1182 uint32_t cbFuture;
1183 if (tsNow < tsTransferNext)
1184 {
1185 /** @todo ASSUMES nanosecond clock ticks, need to make this
1186 * resolution independent. */
1187 cbFuture = PDMAudioPropsNanoToBytes(&pStreamShared->State.Cfg.Props, tsTransferNext - tsNow);
1188 cbFuture = RT_MIN(cbFuture, cbPeriod - cbFrame);
1189 }
1190 else
1191 {
1192 /* We've hit/overshot the timer deadline. Return to ring-3 if we're
1193 not already there to increase the chance that we'll help expidite
1194 the timer. If we're already in ring-3, do all but the last frame. */
1195# ifndef IN_RING3
1196 LogFunc(("[SD%RU8] DMA period expired: tsNow=%RU64 >= tsTransferNext=%RU64 -> VINF_IOM_R3_MMIO_READ\n",
1197 tsNow, tsTransferNext));
1198 return VINF_IOM_R3_MMIO_READ;
1199# else
1200 cbFuture = cbPeriod - cbFrame;
1201 LogFunc(("[SD%RU8] DMA period expired: tsNow=%RU64 >= tsTransferNext=%RU64 -> cbFuture=%#x (cbPeriod=%#x - cbFrame=%#x)\n",
1202 tsNow, tsTransferNext, cbFuture, cbPeriod, cbFrame));
1203# endif
1204 }
1205 uint32_t const offNow = PDMAudioPropsFloorBytesToFrame(&pStreamShared->State.Cfg.Props, cbPeriod - cbFuture);
1206
1207 /*
1208 * Should we transfer a little? Minimum is 64 bytes (semi-random,
1209 * suspect real hardware might be doing some cache aligned stuff,
1210 * which might soon get complicated if you take unaligned buffers
1211 * into consideration and which cache line size (128 bytes is just
1212 * as likely as 64 or 32 bytes)).
1213 */
1214 uint32_t cbDmaTotal = pStreamShared->State.cbDmaTotal;
1215 if (cbDmaTotal + 64 <= offNow)
1216 {
1217 VBOXSTRICTRC rcStrict = hdaStreamDoOnAccessDmaOutput(pDevIns, pThis, pStreamShared,
1218 tsNow, offNow - cbDmaTotal);
1219
1220 /* LPIB is updated by hdaStreamDoOnAccessDmaOutput, so get the new value. */
1221 uint32_t const uNewLpib = HDA_STREAM_REG(pThis, LPIB, uSD);
1222 *pu32Value = uNewLpib;
1223
1224 LogFlowFunc(("[SD%RU8] LPIB=%#RX32 (CBL=%#RX32 PrevLPIB=%#x offNow=%#x) rcStrict=%Rrc\n", uSD,
1225 uNewLpib, HDA_STREAM_REG(pThis, CBL, uSD), uLPIB, offNow, VBOXSTRICTRC_VAL(rcStrict) ));
1226 return rcStrict;
1227 }
1228
1229 /*
1230 * Do nothing, just return LPIB as it is.
1231 */
1232 LogFlowFunc(("[SD%RU8] Skipping DMA transfer: cbDmaTotal=%#x offNow=%#x\n", uSD, cbDmaTotal, offNow));
1233 }
1234 else
1235 LogFunc(("[SD%RU8] cbPeriod=%#x <= cbFrame=%#x!!\n", uSD, cbPeriod, cbFrame));
1236 }
1237 else
1238 LogFunc(("[SD%RU8] fRunning=0 SDnCTL=%#x!!\n", uSD, HDA_STREAM_REG(pThis, CTL, uSD) ));
1239 }
1240#endif /* VBOX_HDA_WITH_ON_REG_ACCESS_DMA */
1241
1242 LogFlowFunc(("[SD%RU8] LPIB=%#RX32 (CBL=%#RX32 CTL=%#RX32)\n",
1243 uSD, uLPIB, HDA_STREAM_REG(pThis, CBL, uSD), HDA_STREAM_REG(pThis, CTL, uSD) ));
1244 *pu32Value = uLPIB;
1245 return VINF_SUCCESS;
1246}
1247
1248/**
1249 * Gets the wall clock.
1250 *
1251 * Used by hdaRegReadWALCLK() and 'info hda'.
1252 *
1253 * @returns Strict VBox status code if @a fDoDma is @c true, otherwise
1254 * VINF_SUCCESS.
1255 * @param pDevIns The device instance.
1256 * @param pThis The shared HDA device state.
1257 * @param fDoDma Whether to consider doing DMA work or not.
1258 * @param puWallNow Where to return the current wall clock time.
1259 */
1260static VBOXSTRICTRC hdaQueryWallClock(PPDMDEVINS pDevIns, PHDASTATE pThis, bool fDoDma, uint64_t *puWallNow)
1261{
1262 /*
1263 * The wall clock is calculated from the virtual sync clock. Since
1264 * the clock is supposed to reset to zero on controller reset, a
1265 * start offset is subtracted.
1266 *
1267 * In addition, we hold the clock back when there are active DMA engines
1268 * so that the guest won't conclude we've gotten further in the buffer
1269 * processing than what we really have. (We generally read a whole buffer
1270 * at once when the IOC is due, so we're a lot later than what real
1271 * hardware would be in reading/writing the buffers.)
1272 *
1273 * Here are some old notes from the DMA engine that might be useful even
1274 * if a little dated:
1275 *
1276 * Note 1) Only certain guests (like Linux' snd_hda_intel) rely on the WALCLK register
1277 * in order to determine the correct timing of the sound device. Other guests
1278 * like Windows 7 + 10 (or even more exotic ones like Haiku) will completely
1279 * ignore this.
1280 *
1281 * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic
1282 * fashion) this *will* upset guest device drivers and will completely fuck up the
1283 * sound output. Running VLC on the guest will tell!
1284 */
1285 uint64_t const uFreq = PDMDevHlpTimerGetFreq(pDevIns, pThis->aStreams[0].hTimer);
1286 Assert(uFreq <= UINT32_MAX);
1287 uint64_t const tsStart = 0; /** @todo pThis->tsWallClkStart (as it is reset on controller reset) */
1288 uint64_t const tsNow = PDMDevHlpTimerGet(pDevIns, pThis->aStreams[0].hTimer);
1289
1290 /* Find the oldest DMA transfer timestamp from the active streams. */
1291 int iDmaNow = -1;
1292 uint64_t tsDmaNow = tsNow;
1293 for (size_t i = 0; i < RT_ELEMENTS(pThis->aStreams); i++)
1294 if (pThis->aStreams[i].State.fRunning)
1295 {
1296#ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
1297 /* Linux is reading WALCLK before one of the DMA position reads and
1298 we've already got the current time from TM, so check if we should
1299 do a little bit of DMA'ing here to help WALCLK ahead. */
1300 if (fDoDma)
1301 {
1302 if (hdaGetDirFromSD((uint8_t)i) == PDMAUDIODIR_OUT)
1303 {
1304 VBOXSTRICTRC rcStrict = hdaStreamMaybeDoOnAccessDmaOutput(pDevIns, pThis, &pThis->aStreams[i], tsNow);
1305 if (rcStrict == VINF_SUCCESS)
1306 { /* likely */ }
1307 else
1308 return rcStrict;
1309 }
1310 }
1311#endif
1312
1313 if ( pThis->aStreams[i].State.tsTransferLast < tsDmaNow
1314 && pThis->aStreams[i].State.tsTransferLast > tsStart)
1315 {
1316 tsDmaNow = pThis->aStreams[i].State.tsTransferLast;
1317 iDmaNow = (int)i;
1318 }
1319 }
1320
1321 /* Convert it to wall clock ticks. */
1322 uint64_t const uWallClkNow = ASMMultU64ByU32DivByU32(tsDmaNow - tsStart,
1323 24000000 /*Wall clock frequency */,
1324 uFreq);
1325 Log3Func(("Returning %#RX64 - tsNow=%#RX64 tsDmaNow=%#RX64 (%d) -> %#RX64\n",
1326 uWallClkNow, tsNow, tsDmaNow, iDmaNow, tsNow - tsDmaNow));
1327 RT_NOREF(iDmaNow, fDoDma);
1328 *puWallNow = uWallClkNow;
1329 return VINF_SUCCESS;
1330}
1331
1332static VBOXSTRICTRC hdaRegReadWALCLK(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
1333{
1334 uint64_t uWallNow = 0;
1335 VBOXSTRICTRC rcStrict = hdaQueryWallClock(pDevIns, pThis, true /*fDoDma*/, &uWallNow);
1336 if (rcStrict == VINF_SUCCESS)
1337 {
1338 *pu32Value = (uint32_t)uWallNow;
1339 return VINF_SUCCESS;
1340 }
1341 RT_NOREF(iReg);
1342 return rcStrict;
1343}
1344
1345static VBOXSTRICTRC hdaRegWriteSSYNC(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1346{
1347 /*
1348 * The SSYNC register is a DMA pause mask where each bit represents a stream.
1349 * There should be no DMA transfers going down the driver chains when the a
1350 * stream has its bit set here. There are two scenarios described in the
1351 * specification, starting and stopping, though it can probably be used for
1352 * other purposes if the guest gets creative...
1353 *
1354 * Anyway, if we ever want to implement this, we'd be manipulating the DMA
1355 * timers of the affected streams here, I think. At least in the start
1356 * scenario, we would run the first DMA transfers from here.
1357 */
1358 uint32_t const fOld = HDA_REG(pThis, SSYNC);
1359 uint32_t const fNew = (u32Value & g_aHdaRegMap[iReg].fWritableMask)
1360 | (fOld & ~g_aHdaRegMap[iReg].fWritableMask);
1361 uint32_t const fChanged = (fNew ^ fOld) & (RT_BIT_32(HDA_MAX_STREAMS) - 1);
1362 if (fChanged)
1363 {
1364#if 0 /** @todo implement SSYNC: ndef IN_RING3 */
1365 RT_NOREF(pDevIns);
1366 Log3Func(("Going to ring-3 to handle SSYNC change: %#x\n", fChanged));
1367 return VINF_IOM_R3_MMIO_WRITE;
1368#else
1369 for (uint32_t fMask = 1, i = 0; fMask < RT_BIT_32(HDA_MAX_STREAMS); i++, fMask <<= 1)
1370 if (!(fChanged & fMask))
1371 { /* nothing */ }
1372 else if (fNew & fMask)
1373 {
1374 Log3Func(("SSYNC bit %u set\n", i));
1375 /* See code in SDCTL around hdaR3StreamTimerMain call. */
1376 }
1377 else
1378 {
1379 Log3Func(("SSYNC bit %u cleared\n", i));
1380 /* The next DMA timer callout will not do anything. */
1381 }
1382 RT_NOREF(pDevIns);
1383#endif
1384 }
1385
1386 HDA_REG(pThis, SSYNC) = fNew;
1387 return VINF_SUCCESS;
1388}
1389
1390static VBOXSTRICTRC hdaRegWriteCORBRP(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1391{
1392 RT_NOREF(pDevIns, iReg);
1393 if (u32Value & HDA_CORBRP_RST)
1394 {
1395 /* Do a CORB reset. */
1396 if (pThis->cbCorbBuf)
1397 RT_ZERO(pThis->au32CorbBuf);
1398
1399 LogRel2(("HDA: CORB reset\n"));
1400 HDA_REG(pThis, CORBRP) = HDA_CORBRP_RST; /* Clears the pointer. */
1401 }
1402 else
1403 HDA_REG(pThis, CORBRP) &= ~HDA_CORBRP_RST; /* Only CORBRP_RST bit is writable. */
1404
1405 return VINF_SUCCESS;
1406}
1407
1408static VBOXSTRICTRC hdaRegWriteCORBCTL(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1409{
1410 VBOXSTRICTRC rc = hdaRegWriteU8(pDevIns, pThis, iReg, u32Value);
1411 AssertRCSuccess(VBOXSTRICTRC_VAL(rc));
1412
1413 if (HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA) /* DMA engine started? */
1414 {
1415#ifdef IN_RING3 /** @todo do PDMDevHlpTaskTrigger everywhere? */
1416 rc = hdaR3CORBCmdProcess(pDevIns, pThis, PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATECC));
1417#else
1418 rc = PDMDevHlpTaskTrigger(pDevIns, pThis->hCorbDmaTask);
1419 if (rc != VINF_SUCCESS && RT_SUCCESS(rc))
1420 rc = VINF_SUCCESS;
1421#endif
1422 }
1423 else
1424 LogFunc(("CORB DMA not running, skipping\n"));
1425
1426 return rc;
1427}
1428
1429static VBOXSTRICTRC hdaRegWriteCORBSIZE(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1430{
1431 RT_NOREF(pDevIns, iReg);
1432
1433 if (!(HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA)) /* Ignore request if CORB DMA engine is (still) running. */
1434 {
1435 u32Value = (u32Value & HDA_CORBSIZE_SZ);
1436
1437 uint16_t cEntries;
1438 switch (u32Value)
1439 {
1440 case 0: /* 8 byte; 2 entries. */
1441 cEntries = 2;
1442 break;
1443 case 1: /* 64 byte; 16 entries. */
1444 cEntries = 16;
1445 break;
1446 case 2: /* 1 KB; 256 entries. */
1447 cEntries = HDA_CORB_SIZE; /* default. */
1448 break;
1449 default:
1450 LogRel(("HDA: Guest tried to set an invalid CORB size (0x%x), keeping default\n", u32Value));
1451 u32Value = 2;
1452 cEntries = HDA_CORB_SIZE; /* Use default size. */
1453 break;
1454 }
1455
1456 uint32_t cbCorbBuf = cEntries * HDA_CORB_ELEMENT_SIZE;
1457 Assert(cbCorbBuf <= sizeof(pThis->au32CorbBuf)); /* paranoia */
1458
1459 if (cbCorbBuf != pThis->cbCorbBuf)
1460 {
1461 RT_ZERO(pThis->au32CorbBuf); /* Clear CORB when setting a new size. */
1462 pThis->cbCorbBuf = cbCorbBuf;
1463 }
1464
1465 LogFunc(("CORB buffer size is now %RU32 bytes (%u entries)\n", pThis->cbCorbBuf, pThis->cbCorbBuf / HDA_CORB_ELEMENT_SIZE));
1466
1467 HDA_REG(pThis, CORBSIZE) = u32Value;
1468 }
1469 else
1470 LogFunc(("CORB DMA is (still) running, skipping\n"));
1471 return VINF_SUCCESS;
1472}
1473
1474static VBOXSTRICTRC hdaRegWriteCORBSTS(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1475{
1476 RT_NOREF(pDevIns, iReg);
1477
1478 uint32_t v = HDA_REG(pThis, CORBSTS);
1479 HDA_REG(pThis, CORBSTS) &= ~(v & u32Value);
1480
1481 return VINF_SUCCESS;
1482}
1483
1484static VBOXSTRICTRC hdaRegWriteCORBWP(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1485{
1486 VBOXSTRICTRC rc = hdaRegWriteU16(pDevIns, pThis, iReg, u32Value);
1487 AssertRCSuccess(VBOXSTRICTRC_VAL(rc));
1488
1489#ifdef IN_RING3 /** @todo do PDMDevHlpTaskTrigger everywhere? */
1490 return hdaR3CORBCmdProcess(pDevIns, pThis, PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATECC));
1491#else
1492 rc = PDMDevHlpTaskTrigger(pDevIns, pThis->hCorbDmaTask);
1493 return RT_SUCCESS(rc) ? VINF_SUCCESS : rc;
1494#endif
1495}
1496
1497static VBOXSTRICTRC hdaRegWriteSDCBL(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1498{
1499 return hdaRegWriteU32(pDevIns, pThis, iReg, u32Value);
1500}
1501
1502static VBOXSTRICTRC hdaRegWriteSDCTL(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1503{
1504#ifdef IN_RING3
1505 /* Get the stream descriptor number. */
1506 const uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, CTL, iReg);
1507 AssertReturn(uSD < RT_ELEMENTS(pThis->aStreams), VERR_INTERNAL_ERROR_3); /* paranoia^2: Bad g_aHdaRegMap. */
1508
1509 /*
1510 * Extract the stream tag the guest wants to use for this specific
1511 * stream descriptor (SDn). This only can happen if the stream is in a non-running
1512 * state, so we're doing the lookup and assignment here.
1513 *
1514 * So depending on the guest OS, SD3 can use stream tag 4, for example.
1515 */
1516 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
1517 uint8_t uTag = (u32Value >> HDA_SDCTL_NUM_SHIFT) & HDA_SDCTL_NUM_MASK;
1518 ASSERT_GUEST_MSG_RETURN(uTag < RT_ELEMENTS(pThisCC->aTags),
1519 ("SD%RU8: Invalid stream tag %RU8 (u32Value=%#x)!\n", uSD, uTag, u32Value),
1520 VINF_SUCCESS /* Always return success to the MMIO handler. */);
1521
1522 PHDASTREAM const pStreamShared = &pThis->aStreams[uSD];
1523 PHDASTREAMR3 const pStreamR3 = &pThisCC->aStreams[uSD];
1524
1525 const bool fRun = RT_BOOL(u32Value & HDA_SDCTL_RUN);
1526 const bool fReset = RT_BOOL(u32Value & HDA_SDCTL_SRST);
1527
1528 /* If the run bit is set, we take the virtual-sync clock lock as well so we
1529 can safely update timers via hdaR3TimerSet if necessary. We need to be
1530 very careful with the fInReset and fInRun indicators here, as they may
1531 change during the relocking if we need to acquire the clock lock. */
1532 const bool fNeedVirtualSyncClockLock = (u32Value & (HDA_SDCTL_RUN | HDA_SDCTL_SRST)) == HDA_SDCTL_RUN
1533 && (HDA_REG_IND(pThis, iReg) & HDA_SDCTL_RUN) == 0;
1534 if (fNeedVirtualSyncClockLock)
1535 {
1536 DEVHDA_UNLOCK(pDevIns, pThis);
1537 DEVHDA_LOCK_BOTH_RETURN(pDevIns, pThis, pStreamShared, VINF_IOM_R3_MMIO_WRITE);
1538 }
1539
1540 const bool fInRun = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_SDCTL_RUN);
1541 const bool fInReset = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_SDCTL_SRST);
1542
1543 /*LogFunc(("[SD%RU8] fRun=%RTbool, fInRun=%RTbool, fReset=%RTbool, fInReset=%RTbool, %R[sdctl]\n",
1544 uSD, fRun, fInRun, fReset, fInReset, u32Value));*/
1545 if (fInReset)
1546 {
1547 ASSERT_GUEST(!fReset);
1548 ASSERT_GUEST(!fInRun && !fRun);
1549
1550 /* Exit reset state. */
1551 ASMAtomicXchgBool(&pStreamShared->State.fInReset, false);
1552
1553 /* Report that we're done resetting this stream by clearing SRST. */
1554 HDA_STREAM_REG(pThis, CTL, uSD) &= ~HDA_SDCTL_SRST;
1555
1556 LogFunc(("[SD%RU8] Reset exit\n", uSD));
1557 }
1558 else if (fReset)
1559 {
1560 /* ICH6 datasheet 18.2.33 says that RUN bit should be cleared before initiation of reset. */
1561 ASSERT_GUEST(!fInRun && !fRun);
1562
1563 LogFunc(("[SD%RU8] Reset enter\n", uSD));
1564
1565 STAM_REL_PROFILE_START_NS(&pStreamR3->State.StatReset, a);
1566 Assert(PDMCritSectIsOwner(&pThis->CritSect));
1567 PAUDMIXSINK const pMixSink = pStreamR3->pMixSink ? pStreamR3->pMixSink->pMixSink : NULL;
1568 if (pMixSink)
1569 AudioMixerSinkLock(pMixSink);
1570
1571 /* Deal with reset while running. */
1572 if (pStreamShared->State.fRunning)
1573 {
1574 int rc2 = hdaR3StreamEnable(pThis, pStreamShared, pStreamR3, false /* fEnable */);
1575 AssertRC(rc2); Assert(!pStreamShared->State.fRunning);
1576 pStreamShared->State.fRunning = false;
1577 }
1578
1579 hdaR3StreamReset(pThis, pThisCC, pStreamShared, pStreamR3, uSD);
1580
1581 if (pMixSink) /* (FYI. pMixSink might not be what pStreamR3->pMixSink->pMixSink points at any longer) */
1582 AudioMixerSinkUnlock(pMixSink);
1583 STAM_REL_PROFILE_STOP_NS(&pStreamR3->State.StatReset, a);
1584 }
1585 else
1586 {
1587 /*
1588 * We enter here to change DMA states only.
1589 */
1590 if (fInRun != fRun)
1591 {
1592 STAM_REL_PROFILE_START_NS((fRun ? &pStreamR3->State.StatStart : &pStreamR3->State.StatStop), r);
1593 Assert(!fReset && !fInReset); /* (code change paranoia, currently impossible ) */
1594 LogFunc(("[SD%RU8] State changed (fRun=%RTbool)\n", uSD, fRun));
1595
1596 Assert(PDMCritSectIsOwner(&pThis->CritSect));
1597 /** @todo bird: It's not clear to me when the pMixSink is actually
1598 * assigned to the stream, so being paranoid till I find out... */
1599 PAUDMIXSINK const pMixSink = pStreamR3->pMixSink ? pStreamR3->pMixSink->pMixSink : NULL;
1600 if (pMixSink)
1601 AudioMixerSinkLock(pMixSink);
1602
1603 int rc2 = VINF_SUCCESS;
1604 if (fRun)
1605 {
1606 if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT)
1607 {
1608 const uint8_t uStripeCtl = ((u32Value >> HDA_SDCTL_STRIPE_SHIFT) & HDA_SDCTL_STRIPE_MASK) + 1;
1609 LogFunc(("[SD%RU8] Using %RU8 SDOs (stripe control)\n", uSD, uStripeCtl));
1610 if (uStripeCtl > 1)
1611 LogRel2(("HDA: Warning: Striping output over more than one SDO for stream #%RU8 currently is not implemented " \
1612 "(%RU8 SDOs requested)\n", uSD, uStripeCtl));
1613 }
1614
1615 /* Assign new values. */
1616 LogFunc(("[SD%RU8] Using stream tag=%RU8\n", uSD, uTag));
1617 PHDATAG pTag = &pThisCC->aTags[uTag];
1618 pTag->uTag = uTag;
1619 pTag->pStreamR3 = &pThisCC->aStreams[uSD];
1620
1621# ifdef LOG_ENABLED
1622 if (LogIsEnabled())
1623 {
1624 PDMAUDIOPCMPROPS Props = { 0 };
1625 rc2 = hdaR3SDFMTToPCMProps(HDA_STREAM_REG(pThis, FMT, uSD), &Props); AssertRC(rc2);
1626 LogFunc(("[SD%RU8] %RU32Hz, %RU8bit, %RU8 channel(s)\n",
1627 uSD, Props.uHz, PDMAudioPropsSampleBits(&Props), PDMAudioPropsChannels(&Props)));
1628 }
1629# endif
1630 /* (Re-)initialize the stream with current values. */
1631 rc2 = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, pStreamR3, uSD);
1632 if ( RT_SUCCESS(rc2)
1633 /* Any vital stream change occurred so that we need to (re-)add the stream to our setup?
1634 * Otherwise just skip this, as this costs a lot of performance. */
1635 /** @todo r=bird: hdaR3StreamSetUp does not return VINF_NO_CHANGE since r142810. */
1636 && rc2 != VINF_NO_CHANGE)
1637 {
1638 /* Remove the old stream from the device setup. */
1639 rc2 = hdaR3RemoveStream(pThisCC, &pStreamShared->State.Cfg);
1640 AssertRC(rc2);
1641
1642 /* Add the stream to the device setup. */
1643 rc2 = hdaR3AddStream(pThisCC, &pStreamShared->State.Cfg);
1644 AssertRC(rc2);
1645 }
1646 }
1647
1648 if (RT_SUCCESS(rc2))
1649 {
1650 /* Enable/disable the stream. */
1651 rc2 = hdaR3StreamEnable(pThis, pStreamShared, pStreamR3, fRun /* fEnable */);
1652 AssertRC(rc2);
1653
1654 if (fRun)
1655 {
1656 /** @todo move this into a HDAStream.cpp function. */
1657 uint64_t tsNow;
1658 if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT)
1659 {
1660 /* Output streams: Avoid going through the timer here by calling the stream's timer
1661 function directly. Should speed up starting the stream transfers. */
1662 tsNow = hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
1663 }
1664 else
1665 {
1666 /* Input streams: Arm the timer and kick the AIO thread. */
1667 tsNow = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer);
1668 pStreamShared->State.tsTransferLast = tsNow; /* for WALCLK */
1669
1670 uint64_t tsTransferNext = tsNow + pStreamShared->State.aSchedule[0].cPeriodTicks;
1671 pStreamShared->State.tsTransferNext = tsTransferNext; /* legacy */
1672 pStreamShared->State.cbCurDmaPeriod = pStreamShared->State.aSchedule[0].cbPeriod;
1673 Log3Func(("[SD%RU8] tsTransferNext=%RU64 (in %RU64)\n",
1674 pStreamShared->u8SD, tsTransferNext, tsTransferNext - tsNow));
1675
1676 int rc = PDMDevHlpTimerSet(pDevIns, pStreamShared->hTimer, tsTransferNext);
1677 AssertRC(rc);
1678
1679 /** @todo we should have a delayed AIO thread kick off, really... */
1680 if (pStreamR3->pMixSink && pStreamR3->pMixSink->pMixSink)
1681 AudioMixerSinkSignalUpdateJob(pStreamR3->pMixSink->pMixSink);
1682 else
1683 AssertFailed();
1684 }
1685 hdaR3StreamMarkStarted(pDevIns, pThis, pStreamShared, tsNow);
1686 }
1687 else
1688 hdaR3StreamMarkStopped(pStreamShared);
1689 }
1690
1691 /* Make sure to leave the lock before (eventually) starting the timer. */
1692 if (pMixSink)
1693 AudioMixerSinkUnlock(pMixSink);
1694 STAM_REL_PROFILE_STOP_NS((fRun ? &pStreamR3->State.StatStart : &pStreamR3->State.StatStop), r);
1695 }
1696 }
1697
1698 if (fNeedVirtualSyncClockLock)
1699 PDMDevHlpTimerUnlockClock(pDevIns, pStreamShared->hTimer); /* Caller will unlock pThis->CritSect. */
1700
1701 return hdaRegWriteU24(pDevIns, pThis, iReg, u32Value);
1702#else /* !IN_RING3 */
1703 RT_NOREF(pDevIns, pThis, iReg, u32Value);
1704 return VINF_IOM_R3_MMIO_WRITE;
1705#endif /* !IN_RING3 */
1706}
1707
1708static VBOXSTRICTRC hdaRegWriteSDSTS(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1709{
1710 uint32_t v = HDA_REG_IND(pThis, iReg);
1711
1712 /* Clear (zero) FIFOE, DESE and BCIS bits when writing 1 to it (6.2.33). */
1713 HDA_REG_IND(pThis, iReg) &= ~(u32Value & v);
1714
1715 HDA_PROCESS_INTERRUPT(pDevIns, pThis);
1716
1717 return VINF_SUCCESS;
1718}
1719
1720static VBOXSTRICTRC hdaRegWriteSDLVI(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1721{
1722 const size_t idxStream = HDA_SD_NUM_FROM_REG(pThis, LVI, iReg);
1723 AssertReturn(idxStream < RT_ELEMENTS(pThis->aStreams), VERR_INTERNAL_ERROR_3); /* paranoia^2: Bad g_aHdaRegMap. */
1724
1725 ASSERT_GUEST_LOGREL_MSG(u32Value <= UINT8_MAX, /* Should be covered by the register write mask, but just to make sure. */
1726 ("LVI for stream #%zu must not be bigger than %RU8\n", idxStream, UINT8_MAX - 1));
1727 return hdaRegWriteU16(pDevIns, pThis, iReg, u32Value);
1728}
1729
1730/**
1731 * Calculates the number of bytes of a FIFOW register.
1732 *
1733 * @return Number of bytes of a given FIFOW register.
1734 * @param u16RegFIFOW FIFOW register to convert.
1735 */
1736uint8_t hdaSDFIFOWToBytes(uint16_t u16RegFIFOW)
1737{
1738 uint32_t cb;
1739 switch (u16RegFIFOW)
1740 {
1741 case HDA_SDFIFOW_8B: cb = 8; break;
1742 case HDA_SDFIFOW_16B: cb = 16; break;
1743 case HDA_SDFIFOW_32B: cb = 32; break;
1744 default:
1745 AssertFailedStmt(cb = 32); /* Paranoia. */
1746 break;
1747 }
1748
1749 Assert(RT_IS_POWER_OF_TWO(cb));
1750 return cb;
1751}
1752
1753static VBOXSTRICTRC hdaRegWriteSDFIFOW(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1754{
1755 size_t const idxStream = HDA_SD_NUM_FROM_REG(pThis, FIFOW, iReg);
1756 AssertReturn(idxStream < RT_ELEMENTS(pThis->aStreams), VERR_INTERNAL_ERROR_3); /* paranoia^2: Bad g_aHdaRegMap. */
1757
1758 if (RT_LIKELY(hdaGetDirFromSD((uint8_t)idxStream) == PDMAUDIODIR_IN)) /* FIFOW for input streams only. */
1759 { /* likely */ }
1760 else
1761 {
1762#ifndef IN_RING0
1763 LogRel(("HDA: Warning: Guest tried to write read-only FIFOW to output stream #%RU8, ignoring\n", idxStream));
1764 return VINF_SUCCESS;
1765#else
1766 return VINF_IOM_R3_MMIO_WRITE; /* (Go to ring-3 for release logging.) */
1767#endif
1768 }
1769
1770 uint16_t u16FIFOW = 0;
1771 switch (u32Value)
1772 {
1773 case HDA_SDFIFOW_8B:
1774 case HDA_SDFIFOW_16B:
1775 case HDA_SDFIFOW_32B:
1776 u16FIFOW = RT_LO_U16(u32Value); /* Only bits 2:0 are used; see ICH-6, 18.2.38. */
1777 break;
1778 default:
1779 ASSERT_GUEST_LOGREL_MSG_FAILED(("Guest tried writing unsupported FIFOW (0x%zx) to stream #%RU8, defaulting to 32 bytes\n",
1780 u32Value, idxStream));
1781 u16FIFOW = HDA_SDFIFOW_32B;
1782 break;
1783 }
1784
1785 pThis->aStreams[idxStream].u8FIFOW = hdaSDFIFOWToBytes(u16FIFOW);
1786 LogFunc(("[SD%zu] Updating FIFOW to %RU8 bytes\n", idxStream, pThis->aStreams[idxStream].u8FIFOW));
1787 return hdaRegWriteU16(pDevIns, pThis, iReg, u16FIFOW);
1788}
1789
1790/**
1791 * @note This method could be called for changing value on Output Streams only (ICH6 datasheet 18.2.39).
1792 */
1793static VBOXSTRICTRC hdaRegWriteSDFIFOS(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
1794{
1795 uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, FIFOS, iReg);
1796
1797 ASSERT_GUEST_LOGREL_MSG_RETURN(hdaGetDirFromSD(uSD) == PDMAUDIODIR_OUT, /* FIFOS for output streams only. */
1798 ("Guest tried writing read-only FIFOS to input stream #%RU8, ignoring\n", uSD),
1799 VINF_SUCCESS);
1800
1801 uint32_t u32FIFOS;
1802 switch (u32Value)
1803 {
1804 case HDA_SDOFIFO_16B:
1805 case HDA_SDOFIFO_32B:
1806 case HDA_SDOFIFO_64B:
1807 case HDA_SDOFIFO_128B:
1808 case HDA_SDOFIFO_192B:
1809 case HDA_SDOFIFO_256B:
1810 u32FIFOS = u32Value;
1811 break;
1812
1813 default:
1814 ASSERT_GUEST_LOGREL_MSG_FAILED(("Guest tried writing unsupported FIFOS (0x%x) to stream #%RU8, defaulting to 192 bytes\n",
1815 u32Value, uSD));
1816 u32FIFOS = HDA_SDOFIFO_192B;
1817 break;
1818 }
1819
1820 return hdaRegWriteU16(pDevIns, pThis, iReg, u32FIFOS);
1821}
1822
1823#ifdef IN_RING3
1824
1825/**
1826 * Adds an audio output stream to the device setup using the given configuration.
1827 *
1828 * @returns VBox status code.
1829 * @param pThisCC The ring-3 HDA device state.
1830 * @param pCfg Stream configuration to use for adding a stream.
1831 */
1832static int hdaR3AddStreamOut(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg)
1833{
1834 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1835
1836 AssertReturn(pCfg->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER);
1837
1838 LogFlowFunc(("Stream=%s\n", pCfg->szName));
1839
1840 int rc = VINF_SUCCESS;
1841
1842 bool fUseFront = true; /* Always use front out by default. */
1843# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
1844 bool fUseRear;
1845 bool fUseCenter;
1846 bool fUseLFE;
1847
1848 fUseRear = fUseCenter = fUseLFE = false;
1849
1850 /*
1851 * Use commonly used setups for speaker configurations.
1852 */
1853
1854 /** @todo Make the following configurable through mixer API and/or CFGM? */
1855 switch (PDMAudioPropsChannels(&pCfg->Props))
1856 {
1857 case 3: /* 2.1: Front (Stereo) + LFE. */
1858 {
1859 fUseLFE = true;
1860 break;
1861 }
1862
1863 case 4: /* Quadrophonic: Front (Stereo) + Rear (Stereo). */
1864 {
1865 fUseRear = true;
1866 break;
1867 }
1868
1869 case 5: /* 4.1: Front (Stereo) + Rear (Stereo) + LFE. */
1870 {
1871 fUseRear = true;
1872 fUseLFE = true;
1873 break;
1874 }
1875
1876 case 6: /* 5.1: Front (Stereo) + Rear (Stereo) + Center/LFE. */
1877 {
1878 fUseRear = true;
1879 fUseCenter = true;
1880 fUseLFE = true;
1881 break;
1882 }
1883
1884 default: /* Unknown; fall back to 2 front channels (stereo). */
1885 {
1886 rc = VERR_NOT_SUPPORTED;
1887 break;
1888 }
1889 }
1890# endif /* !VBOX_WITH_AUDIO_HDA_51_SURROUND */
1891
1892 if (rc == VERR_NOT_SUPPORTED)
1893 {
1894 LogRel2(("HDA: Warning: Unsupported channel count (%RU8), falling back to stereo channels (2)\n",
1895 PDMAudioPropsChannels(&pCfg->Props) ));
1896
1897 /* Fall back to 2 channels (see below in fUseFront block). */
1898 rc = VINF_SUCCESS;
1899 }
1900
1901 do
1902 {
1903 if (RT_FAILURE(rc))
1904 break;
1905
1906 if (fUseFront)
1907 {
1908 RTStrPrintf(pCfg->szName, RT_ELEMENTS(pCfg->szName), "Front");
1909
1910 pCfg->enmPath = PDMAUDIOPATH_OUT_FRONT;
1911 /// @todo PDMAudioPropsSetChannels(&pCfg->Props, 2); ?
1912
1913 rc = hdaR3CodecAddStream(&pThisCC->Codec, PDMAUDIOMIXERCTL_FRONT, pCfg);
1914 }
1915
1916# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
1917 if ( RT_SUCCESS(rc)
1918 && (fUseCenter || fUseLFE))
1919 {
1920 RTStrPrintf(pCfg->szName, RT_ELEMENTS(pCfg->szName), "Center/LFE");
1921
1922 pCfg->enmPath = PDMAUDIOPATH_OUT_CENTER_LFE;
1923 PDMAudioPropsSetChannels(&pCfg->Props, fUseCenter && fUseLFE ? 2 : 1);
1924
1925 rc = hdaR3CodecAddStream(&pThisCC->Codec, PDMAUDIOMIXERCTL_CENTER_LFE, pCfg);
1926 }
1927
1928 if ( RT_SUCCESS(rc)
1929 && fUseRear)
1930 {
1931 RTStrPrintf(pCfg->szName, RT_ELEMENTS(pCfg->szName), "Rear");
1932
1933 pCfg->enmPath = PDMAUDIOPATH_OUT_REAR;
1934 PDMAudioPropsSetChannels(&pCfg->Props, 2);
1935
1936 rc = hdaR3CodecAddStream(&pThisCC->Codec, PDMAUDIOMIXERCTL_REAR, pCfg);
1937 }
1938# endif /* VBOX_WITH_AUDIO_HDA_51_SURROUND */
1939
1940 } while (0);
1941
1942 LogFlowFuncLeaveRC(rc);
1943 return rc;
1944}
1945
1946/**
1947 * Adds an audio input stream to the device setup using the given configuration.
1948 *
1949 * @returns VBox status code.
1950 * @param pThisCC The ring-3 HDA device state.
1951 * @param pCfg Stream configuration to use for adding a stream.
1952 */
1953static int hdaR3AddStreamIn(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg)
1954{
1955 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1956
1957 AssertReturn(pCfg->enmDir == PDMAUDIODIR_IN, VERR_INVALID_PARAMETER);
1958
1959 LogFlowFunc(("Stream=%s enmPath=%ld\n", pCfg->szName, pCfg->enmPath));
1960
1961 int rc;
1962 switch (pCfg->enmPath)
1963 {
1964 case PDMAUDIOPATH_IN_LINE:
1965 rc = hdaR3CodecAddStream(&pThisCC->Codec, PDMAUDIOMIXERCTL_LINE_IN, pCfg);
1966 break;
1967# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
1968 case PDMAUDIOPATH_IN_MIC:
1969 rc = hdaR3CodecAddStream(&pThisCC->Codec, PDMAUDIOMIXERCTL_MIC_IN, pCfg);
1970 break;
1971# endif
1972 default:
1973 rc = VERR_NOT_SUPPORTED;
1974 break;
1975 }
1976
1977 LogFlowFuncLeaveRC(rc);
1978 return rc;
1979}
1980
1981/**
1982 * Adds an audio stream to the device setup using the given configuration.
1983 *
1984 * @returns VBox status code.
1985 * @param pThisCC The ring-3 HDA device state.
1986 * @param pCfg Stream configuration to use for adding a stream.
1987 */
1988static int hdaR3AddStream(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg)
1989{
1990 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1991
1992 LogFlowFuncEnter();
1993
1994 int rc;
1995 switch (pCfg->enmDir)
1996 {
1997 case PDMAUDIODIR_OUT:
1998 rc = hdaR3AddStreamOut(pThisCC, pCfg);
1999 break;
2000
2001 case PDMAUDIODIR_IN:
2002 rc = hdaR3AddStreamIn(pThisCC, pCfg);
2003 break;
2004
2005 default:
2006 rc = VERR_NOT_SUPPORTED;
2007 AssertFailed();
2008 break;
2009 }
2010
2011 LogFlowFunc(("Returning %Rrc\n", rc));
2012
2013 return rc;
2014}
2015
2016/**
2017 * Removes an audio stream from the device setup using the given configuration.
2018 *
2019 * Used by hdaRegWriteSDCTL().
2020 *
2021 * @returns VBox status code.
2022 * @param pThisCC The ring-3 HDA device state.
2023 * @param pCfg Stream configuration to use for removing a stream.
2024 */
2025static int hdaR3RemoveStream(PHDASTATER3 pThisCC, PPDMAUDIOSTREAMCFG pCfg)
2026{
2027 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2028
2029 int rc = VINF_SUCCESS;
2030
2031 PDMAUDIOMIXERCTL enmMixerCtl = PDMAUDIOMIXERCTL_UNKNOWN;
2032 switch (pCfg->enmDir)
2033 {
2034 case PDMAUDIODIR_IN:
2035 {
2036 LogFlowFunc(("Stream=%s enmPath=%d (src)\n", pCfg->szName, pCfg->enmPath));
2037
2038 switch (pCfg->enmPath)
2039 {
2040 case PDMAUDIOPATH_UNKNOWN: break;
2041 case PDMAUDIOPATH_IN_LINE: enmMixerCtl = PDMAUDIOMIXERCTL_LINE_IN; break;
2042# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2043 case PDMAUDIOPATH_IN_MIC: enmMixerCtl = PDMAUDIOMIXERCTL_MIC_IN; break;
2044# endif
2045 default:
2046 rc = VERR_NOT_SUPPORTED;
2047 break;
2048 }
2049 break;
2050 }
2051
2052 case PDMAUDIODIR_OUT:
2053 {
2054 LogFlowFunc(("Stream=%s, enmPath=%d (dst)\n", pCfg->szName, pCfg->enmPath));
2055
2056 switch (pCfg->enmPath)
2057 {
2058 case PDMAUDIOPATH_UNKNOWN: break;
2059 case PDMAUDIOPATH_OUT_FRONT: enmMixerCtl = PDMAUDIOMIXERCTL_FRONT; break;
2060# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2061 case PDMAUDIOPATH_OUT_CENTER_LFE: enmMixerCtl = PDMAUDIOMIXERCTL_CENTER_LFE; break;
2062 case PDMAUDIOPATH_OUT_REAR: enmMixerCtl = PDMAUDIOMIXERCTL_REAR; break;
2063# endif
2064 default:
2065 rc = VERR_NOT_SUPPORTED;
2066 break;
2067 }
2068 break;
2069 }
2070
2071 default:
2072 rc = VERR_NOT_SUPPORTED;
2073 break;
2074 }
2075
2076 if ( RT_SUCCESS(rc)
2077 && enmMixerCtl != PDMAUDIOMIXERCTL_UNKNOWN)
2078 {
2079 rc = hdaR3CodecRemoveStream(&pThisCC->Codec, enmMixerCtl, false /*fImmediate*/);
2080 }
2081
2082 LogFlowFuncLeaveRC(rc);
2083 return rc;
2084}
2085
2086#endif /* IN_RING3 */
2087
2088static VBOXSTRICTRC hdaRegWriteSDFMT(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
2089{
2090#ifdef IN_RING3
2091 PDMAUDIOPCMPROPS Props;
2092 int rc2 = hdaR3SDFMTToPCMProps(RT_LO_U16(u32Value), &Props);
2093 AssertRC(rc2);
2094 LogFunc(("[SD%RU8] Set to %#x (%RU32Hz, %RU8bit, %RU8 channel(s))\n", HDA_SD_NUM_FROM_REG(pThis, FMT, iReg), u32Value,
2095 PDMAudioPropsHz(&Props), PDMAudioPropsSampleBits(&Props), PDMAudioPropsChannels(&Props)));
2096
2097 /*
2098 * Write the wanted stream format into the register in any case.
2099 *
2100 * This is important for e.g. MacOS guests, as those try to initialize streams which are not reported
2101 * by the device emulation (wants 4 channels, only have 2 channels at the moment).
2102 *
2103 * When ignoring those (invalid) formats, this leads to MacOS thinking that the device is malfunctioning
2104 * and therefore disabling the device completely.
2105 */
2106 return hdaRegWriteU16(pDevIns, pThis, iReg, u32Value);
2107#else
2108 RT_NOREF(pDevIns, pThis, iReg, u32Value);
2109 return VINF_IOM_R3_MMIO_WRITE;
2110#endif
2111}
2112
2113/**
2114 * Worker for writes to the BDPL and BDPU registers.
2115 */
2116DECLINLINE(VBOXSTRICTRC) hdaRegWriteSDBDPX(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value, uint8_t uSD)
2117{
2118 RT_NOREF(uSD);
2119 return hdaRegWriteU32(pDevIns, pThis, iReg, u32Value);
2120}
2121
2122static VBOXSTRICTRC hdaRegWriteSDBDPL(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
2123{
2124 return hdaRegWriteSDBDPX(pDevIns, pThis, iReg, u32Value, HDA_SD_NUM_FROM_REG(pThis, BDPL, iReg));
2125}
2126
2127static VBOXSTRICTRC hdaRegWriteSDBDPU(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
2128{
2129 return hdaRegWriteSDBDPX(pDevIns, pThis, iReg, u32Value, HDA_SD_NUM_FROM_REG(pThis, BDPU, iReg));
2130}
2131
2132static VBOXSTRICTRC hdaRegReadIRS(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
2133{
2134 /* regarding 3.4.3 we should mark IRS as busy in case CORB is active */
2135 if ( HDA_REG(pThis, CORBWP) != HDA_REG(pThis, CORBRP)
2136 || (HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA))
2137 HDA_REG(pThis, IRS) = HDA_IRS_ICB; /* busy */
2138
2139 return hdaRegReadU32(pDevIns, pThis, iReg, pu32Value);
2140}
2141
2142static VBOXSTRICTRC hdaRegWriteIRS(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
2143{
2144 RT_NOREF(pDevIns, iReg);
2145
2146 /*
2147 * If the guest set the ICB bit of IRS register, HDA should process the verb in IC register,
2148 * write the response to IR register, and set the IRV (valid in case of success) bit of IRS register.
2149 */
2150 if ( (u32Value & HDA_IRS_ICB)
2151 && !(HDA_REG(pThis, IRS) & HDA_IRS_ICB))
2152 {
2153#ifdef IN_RING3
2154 uint32_t uCmd = HDA_REG(pThis, IC);
2155
2156 if (HDA_REG(pThis, CORBWP) != HDA_REG(pThis, CORBRP))
2157 {
2158 /*
2159 * 3.4.3: Defines behavior of immediate Command status register.
2160 */
2161 LogRel(("HDA: Guest attempted process immediate verb (%x) with active CORB\n", uCmd));
2162 return VINF_SUCCESS;
2163 }
2164
2165 HDA_REG(pThis, IRS) = HDA_IRS_ICB; /* busy */
2166
2167 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
2168 uint64_t uResp = 0;
2169 int rc2 = pThisCC->Codec.pfnLookup(&pThisCC->Codec, HDA_CODEC_CMD(uCmd, 0 /* LUN */), &uResp);
2170 if (RT_FAILURE(rc2))
2171 LogFunc(("Codec lookup failed with rc2=%Rrc\n", rc2));
2172
2173 HDA_REG(pThis, IR) = (uint32_t)uResp; /** @todo r=andy Do we need a 64-bit response? */
2174 HDA_REG(pThis, IRS) = HDA_IRS_IRV; /* result is ready */
2175 /** @todo r=michaln We just set the IRS value, why are we clearing unset bits? */
2176 HDA_REG(pThis, IRS) &= ~HDA_IRS_ICB; /* busy is clear */
2177
2178 return VINF_SUCCESS;
2179#else /* !IN_RING3 */
2180 return VINF_IOM_R3_MMIO_WRITE;
2181#endif /* !IN_RING3 */
2182 }
2183
2184 /*
2185 * Once the guest read the response, it should clear the IRV bit of the IRS register.
2186 */
2187 HDA_REG(pThis, IRS) &= ~(u32Value & HDA_IRS_IRV);
2188 return VINF_SUCCESS;
2189}
2190
2191static VBOXSTRICTRC hdaRegWriteRIRBWP(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
2192{
2193 RT_NOREF(pDevIns, iReg);
2194
2195 if (HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA) /* Ignore request if CORB DMA engine is (still) running. */
2196 LogFunc(("CORB DMA (still) running, skipping\n"));
2197 else
2198 {
2199 if (u32Value & HDA_RIRBWP_RST)
2200 {
2201 /* Do a RIRB reset. */
2202 if (pThis->cbRirbBuf)
2203 RT_ZERO(pThis->au64RirbBuf);
2204
2205 LogRel2(("HDA: RIRB reset\n"));
2206
2207 HDA_REG(pThis, RIRBWP) = 0;
2208 }
2209 /* The remaining bits are O, see 6.2.22. */
2210 }
2211 return VINF_SUCCESS;
2212}
2213
2214static VBOXSTRICTRC hdaRegWriteRINTCNT(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
2215{
2216 RT_NOREF(pDevIns);
2217 if (HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA) /* Ignore request if CORB DMA engine is (still) running. */
2218 {
2219 LogFunc(("CORB DMA is (still) running, skipping\n"));
2220 return VINF_SUCCESS;
2221 }
2222
2223 VBOXSTRICTRC rc = hdaRegWriteU16(pDevIns, pThis, iReg, u32Value);
2224 AssertRC(VBOXSTRICTRC_VAL(rc));
2225
2226 /** @todo r=bird: Shouldn't we make sure the HDASTATE::u16RespIntCnt is below
2227 * the new RINTCNT value? Or alterantively, make the DMA look take
2228 * this into account instead... I'll do the later for now. */
2229
2230 LogFunc(("Response interrupt count is now %RU8\n", HDA_REG(pThis, RINTCNT) & 0xFF));
2231 return rc;
2232}
2233
2234static VBOXSTRICTRC hdaRegWriteBase(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
2235{
2236 RT_NOREF(pDevIns);
2237
2238 VBOXSTRICTRC rc = hdaRegWriteU32(pDevIns, pThis, iReg, u32Value);
2239 AssertRCSuccess(VBOXSTRICTRC_VAL(rc));
2240
2241 uint32_t const iRegMem = g_aHdaRegMap[iReg].idxReg;
2242 switch (iReg)
2243 {
2244 case HDA_REG_CORBLBASE:
2245 pThis->u64CORBBase &= UINT64_C(0xFFFFFFFF00000000);
2246 pThis->u64CORBBase |= pThis->au32Regs[iRegMem];
2247 break;
2248 case HDA_REG_CORBUBASE:
2249 pThis->u64CORBBase &= UINT64_C(0x00000000FFFFFFFF);
2250 pThis->u64CORBBase |= (uint64_t)pThis->au32Regs[iRegMem] << 32;
2251 break;
2252 case HDA_REG_RIRBLBASE:
2253 pThis->u64RIRBBase &= UINT64_C(0xFFFFFFFF00000000);
2254 pThis->u64RIRBBase |= pThis->au32Regs[iRegMem];
2255 break;
2256 case HDA_REG_RIRBUBASE:
2257 pThis->u64RIRBBase &= UINT64_C(0x00000000FFFFFFFF);
2258 pThis->u64RIRBBase |= (uint64_t)pThis->au32Regs[iRegMem] << 32;
2259 break;
2260 case HDA_REG_DPLBASE:
2261 pThis->u64DPBase = pThis->au32Regs[iRegMem] & DPBASE_ADDR_MASK;
2262 Assert(pThis->u64DPBase % 128 == 0); /* Must be 128-byte aligned. */
2263
2264 /* Also make sure to handle the DMA position enable bit. */
2265 pThis->fDMAPosition = pThis->au32Regs[iRegMem] & RT_BIT_32(0);
2266
2267#ifndef IN_RING0
2268 LogRel(("HDA: DP base (lower) set: %#RGp\n", pThis->u64DPBase));
2269 LogRel(("HDA: DMA position buffer is %s\n", pThis->fDMAPosition ? "enabled" : "disabled"));
2270#else
2271 return VINF_IOM_R3_MMIO_WRITE; /* (Go to ring-3 for release logging.) */
2272#endif
2273 break;
2274 case HDA_REG_DPUBASE:
2275 pThis->u64DPBase = RT_MAKE_U64(RT_LO_U32(pThis->u64DPBase) & DPBASE_ADDR_MASK, pThis->au32Regs[iRegMem]);
2276#ifndef IN_RING0
2277 LogRel(("HDA: DP base (upper) set: %#RGp\n", pThis->u64DPBase));
2278#else
2279 return VINF_IOM_R3_MMIO_WRITE; /* (Go to ring-3 for release logging.) */
2280#endif
2281 break;
2282 default:
2283 AssertMsgFailed(("Invalid index\n"));
2284 break;
2285 }
2286
2287 LogFunc(("CORB base:%llx RIRB base: %llx DP base: %llx\n",
2288 pThis->u64CORBBase, pThis->u64RIRBBase, pThis->u64DPBase));
2289 return rc;
2290}
2291
2292static VBOXSTRICTRC hdaRegWriteRIRBSTS(PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
2293{
2294 RT_NOREF(pDevIns, iReg);
2295
2296 uint8_t v = HDA_REG(pThis, RIRBSTS);
2297 HDA_REG(pThis, RIRBSTS) &= ~(v & u32Value);
2298
2299 HDA_PROCESS_INTERRUPT(pDevIns, pThis);
2300 return VINF_SUCCESS;
2301}
2302
2303#ifdef IN_RING3
2304
2305/**
2306 * Retrieves a corresponding sink for a given mixer control.
2307 *
2308 * @return Pointer to the sink, NULL if no sink is found.
2309 * @param pThisCC The ring-3 HDA device state.
2310 * @param enmMixerCtl Mixer control to get the corresponding sink for.
2311 */
2312static PHDAMIXERSINK hdaR3MixerControlToSink(PHDASTATER3 pThisCC, PDMAUDIOMIXERCTL enmMixerCtl)
2313{
2314 PHDAMIXERSINK pSink;
2315
2316 switch (enmMixerCtl)
2317 {
2318 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
2319 /* Fall through is intentional. */
2320 case PDMAUDIOMIXERCTL_FRONT:
2321 pSink = &pThisCC->SinkFront;
2322 break;
2323# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2324 case PDMAUDIOMIXERCTL_CENTER_LFE:
2325 pSink = &pThisCC->SinkCenterLFE;
2326 break;
2327 case PDMAUDIOMIXERCTL_REAR:
2328 pSink = &pThisCC->SinkRear;
2329 break;
2330# endif
2331 case PDMAUDIOMIXERCTL_LINE_IN:
2332 pSink = &pThisCC->SinkLineIn;
2333 break;
2334# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2335 case PDMAUDIOMIXERCTL_MIC_IN:
2336 pSink = &pThisCC->SinkMicIn;
2337 break;
2338# endif
2339 default:
2340 AssertMsgFailed(("Unhandled mixer control\n"));
2341 pSink = NULL;
2342 break;
2343 }
2344
2345 return pSink;
2346}
2347
2348/**
2349 * Adds a specific HDA driver to the driver chain.
2350 *
2351 * @returns VBox status code.
2352 * @param pDevIns The HDA device instance.
2353 * @param pThisCC The ring-3 HDA device state.
2354 * @param pDrv HDA driver to add.
2355 */
2356static int hdaR3MixerAddDrv(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PHDADRIVER pDrv)
2357{
2358 int rc = VINF_SUCCESS;
2359
2360 PHDASTREAM pStream = pThisCC->SinkLineIn.pStreamShared;
2361 if ( pStream
2362 && AudioHlpStreamCfgIsValid(&pStream->State.Cfg))
2363 {
2364 int rc2 = hdaR3MixerAddDrvStream(pDevIns, pThisCC->SinkLineIn.pMixSink, &pStream->State.Cfg, pDrv);
2365 if (RT_SUCCESS(rc))
2366 rc = rc2;
2367 }
2368
2369# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2370 pStream = pThisCC->SinkMicIn.pStreamShared;
2371 if ( pStream
2372 && AudioHlpStreamCfgIsValid(&pStream->State.Cfg))
2373 {
2374 int rc2 = hdaR3MixerAddDrvStream(pDevIns, pThisCC->SinkMicIn.pMixSink, &pStream->State.Cfg, pDrv);
2375 if (RT_SUCCESS(rc))
2376 rc = rc2;
2377 }
2378# endif
2379
2380 pStream = pThisCC->SinkFront.pStreamShared;
2381 if ( pStream
2382 && AudioHlpStreamCfgIsValid(&pStream->State.Cfg))
2383 {
2384 int rc2 = hdaR3MixerAddDrvStream(pDevIns, pThisCC->SinkFront.pMixSink, &pStream->State.Cfg, pDrv);
2385 if (RT_SUCCESS(rc))
2386 rc = rc2;
2387 }
2388
2389# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2390 pStream = pThisCC->SinkCenterLFE.pStreamShared;
2391 if ( pStream
2392 && AudioHlpStreamCfgIsValid(&pStream->State.Cfg))
2393 {
2394 int rc2 = hdaR3MixerAddDrvStream(pDevIns, pThisCC->SinkCenterLFE.pMixSink, &pStream->State.Cfg, pDrv);
2395 if (RT_SUCCESS(rc))
2396 rc = rc2;
2397 }
2398
2399 pStream = pThisCC->SinkRear.pStreamShared;
2400 if ( pStream
2401 && AudioHlpStreamCfgIsValid(&pStream->State.Cfg))
2402 {
2403 int rc2 = hdaR3MixerAddDrvStream(pDevIns, pThisCC->SinkRear.pMixSink, &pStream->State.Cfg, pDrv);
2404 if (RT_SUCCESS(rc))
2405 rc = rc2;
2406 }
2407# endif
2408
2409 return rc;
2410}
2411
2412/**
2413 * Removes a specific HDA driver from the driver chain and destroys its
2414 * associated streams.
2415 *
2416 * @param pDevIns The device instance.
2417 * @param pThisCC The ring-3 HDA device state.
2418 * @param pDrv HDA driver to remove.
2419 */
2420static void hdaR3MixerRemoveDrv(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PHDADRIVER pDrv)
2421{
2422 AssertPtrReturnVoid(pDrv);
2423
2424 if (pDrv->LineIn.pMixStrm)
2425 {
2426 AudioMixerSinkRemoveStream(pThisCC->SinkLineIn.pMixSink, pDrv->LineIn.pMixStrm);
2427 AudioMixerStreamDestroy(pDrv->LineIn.pMixStrm, pDevIns, true /*fImmediate*/);
2428 pDrv->LineIn.pMixStrm = NULL;
2429 }
2430
2431# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2432 if (pDrv->MicIn.pMixStrm)
2433 {
2434 AudioMixerSinkRemoveStream(pThisCC->SinkMicIn.pMixSink, pDrv->MicIn.pMixStrm);
2435 AudioMixerStreamDestroy(pDrv->MicIn.pMixStrm, pDevIns, true /*fImmediate*/);
2436 pDrv->MicIn.pMixStrm = NULL;
2437 }
2438# endif
2439
2440 if (pDrv->Front.pMixStrm)
2441 {
2442 AudioMixerSinkRemoveStream(pThisCC->SinkFront.pMixSink, pDrv->Front.pMixStrm);
2443 AudioMixerStreamDestroy(pDrv->Front.pMixStrm, pDevIns, true /*fImmediate*/);
2444 pDrv->Front.pMixStrm = NULL;
2445 }
2446
2447# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2448 if (pDrv->CenterLFE.pMixStrm)
2449 {
2450 AudioMixerSinkRemoveStream(pThisCC->SinkCenterLFE.pMixSink, pDrv->CenterLFE.pMixStrm);
2451 AudioMixerStreamDestroy(pDrv->CenterLFE.pMixStrm, pDevIns, true /*fImmediate*/);
2452 pDrv->CenterLFE.pMixStrm = NULL;
2453 }
2454
2455 if (pDrv->Rear.pMixStrm)
2456 {
2457 AudioMixerSinkRemoveStream(pThisCC->SinkRear.pMixSink, pDrv->Rear.pMixStrm);
2458 AudioMixerStreamDestroy(pDrv->Rear.pMixStrm, pDevIns, true /*fImmediate*/);
2459 pDrv->Rear.pMixStrm = NULL;
2460 }
2461# endif
2462
2463 RTListNodeRemove(&pDrv->Node);
2464}
2465
2466/**
2467 * Adds a driver stream to a specific mixer sink.
2468 *
2469 * @returns VBox status code (ignored by caller).
2470 * @param pDevIns The HDA device instance.
2471 * @param pMixSink Audio mixer sink to add audio streams to.
2472 * @param pCfg Audio stream configuration to use for the audio
2473 * streams to add.
2474 * @param pDrv Driver stream to add.
2475 */
2476static int hdaR3MixerAddDrvStream(PPDMDEVINS pDevIns, PAUDMIXSINK pMixSink, PCPDMAUDIOSTREAMCFG pCfg, PHDADRIVER pDrv)
2477{
2478 AssertPtrReturn(pMixSink, VERR_INVALID_POINTER);
2479 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2480
2481 LogFunc(("szSink=%s, szStream=%s, cChannels=%RU8\n", pMixSink->pszName, pCfg->szName, PDMAudioPropsChannels(&pCfg->Props)));
2482
2483 /*
2484 * Get the matching stream driver.
2485 */
2486 PHDADRIVERSTREAM pDrvStream = NULL;
2487 if (pCfg->enmDir == PDMAUDIODIR_IN)
2488 {
2489 LogFunc(("enmPath=%d (src)\n", pCfg->enmPath));
2490 switch (pCfg->enmPath)
2491 {
2492 case PDMAUDIOPATH_IN_LINE:
2493 pDrvStream = &pDrv->LineIn;
2494 break;
2495# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2496 case PDMAUDIOPATH_IN_MIC:
2497 pDrvStream = &pDrv->MicIn;
2498 break;
2499# endif
2500 default:
2501 LogFunc(("returns VERR_NOT_SUPPORTED - enmPath=%d\n", pCfg->enmPath));
2502 return VERR_NOT_SUPPORTED;
2503 }
2504 }
2505 else if (pCfg->enmDir == PDMAUDIODIR_OUT)
2506 {
2507 LogFunc(("enmDst=%d %s (dst)\n", pCfg->enmPath, PDMAudioPathGetName(pCfg->enmPath)));
2508 switch (pCfg->enmPath)
2509 {
2510 case PDMAUDIOPATH_OUT_FRONT:
2511 pDrvStream = &pDrv->Front;
2512 break;
2513# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2514 case PDMAUDIOPATH_OUT_CENTER_LFE:
2515 pDrvStream = &pDrv->CenterLFE;
2516 break;
2517 case PDMAUDIOPATH_OUT_REAR:
2518 pDrvStream = &pDrv->Rear;
2519 break;
2520# endif
2521 default:
2522 LogFunc(("returns VERR_NOT_SUPPORTED - enmPath=%d %s\n", pCfg->enmPath, PDMAudioPathGetName(pCfg->enmPath)));
2523 return VERR_NOT_SUPPORTED;
2524 }
2525 }
2526 else
2527 AssertFailedReturn(VERR_NOT_SUPPORTED);
2528
2529 LogFunc(("[LUN#%RU8] %s\n", pDrv->uLUN, pCfg->szName));
2530
2531 AssertPtr(pDrvStream);
2532 AssertMsg(pDrvStream->pMixStrm == NULL, ("[LUN#%RU8] Driver stream already present when it must not\n", pDrv->uLUN));
2533
2534 PAUDMIXSTREAM pMixStrm = NULL;
2535 int rc = AudioMixerSinkCreateStream(pMixSink, pDrv->pConnector, pCfg, pDevIns, &pMixStrm);
2536 LogFlowFunc(("LUN#%RU8: Created stream \"%s\" for sink, rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc));
2537 if (RT_SUCCESS(rc))
2538 {
2539 rc = AudioMixerSinkAddStream(pMixSink, pMixStrm);
2540 LogFlowFunc(("LUN#%RU8: Added stream \"%s\" to sink, rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc));
2541 if (RT_FAILURE(rc))
2542 AudioMixerStreamDestroy(pMixStrm, pDevIns, true /*fImmediate*/);
2543 }
2544
2545 if (RT_SUCCESS(rc))
2546 pDrvStream->pMixStrm = pMixStrm;
2547
2548 LogFlowFuncLeaveRC(rc);
2549 return rc;
2550}
2551
2552/**
2553 * Adds all current driver streams to a specific mixer sink.
2554 *
2555 * @returns VBox status code.
2556 * @param pDevIns The HDA device instance.
2557 * @param pThisCC The ring-3 HDA device state.
2558 * @param pMixSink Audio mixer sink to add stream to.
2559 * @param pCfg Audio stream configuration to use for the audio streams
2560 * to add.
2561 */
2562static int hdaR3MixerAddDrvStreams(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PAUDMIXSINK pMixSink, PCPDMAUDIOSTREAMCFG pCfg)
2563{
2564 AssertPtrReturn(pMixSink, VERR_INVALID_POINTER);
2565 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2566
2567 LogFunc(("Sink=%s, Stream=%s\n", pMixSink->pszName, pCfg->szName));
2568
2569 int rc;
2570 if (AudioHlpStreamCfgIsValid(pCfg))
2571 {
2572 rc = AudioMixerSinkSetFormat(pMixSink, &pCfg->Props, pCfg->Device.cMsSchedulingHint);
2573 if (RT_SUCCESS(rc))
2574 {
2575 PHDADRIVER pDrv;
2576 RTListForEach(&pThisCC->lstDrv, pDrv, HDADRIVER, Node)
2577 {
2578 /* We ignore failures here because one non-working driver shouldn't
2579 be allowed to spoil it for everyone else. */
2580 int rc2 = hdaR3MixerAddDrvStream(pDevIns, pMixSink, pCfg, pDrv);
2581 if (RT_FAILURE(rc2))
2582 LogFunc(("Attaching stream failed with %Rrc (ignored)\n", rc2));
2583 }
2584 }
2585 }
2586 else
2587 rc = VERR_INVALID_PARAMETER;
2588 return rc;
2589}
2590
2591/**
2592 * @interface_method_impl{HDACODECR3,pfnCbMixerAddStream}
2593 */
2594static DECLCALLBACK(int) hdaR3MixerAddStream(PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl, PCPDMAUDIOSTREAMCFG pCfg)
2595{
2596 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
2597 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2598
2599 int rc;
2600 PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThisCC, enmMixerCtl);
2601 if (pSink)
2602 {
2603 rc = hdaR3MixerAddDrvStreams(pDevIns, pThisCC, pSink->pMixSink, pCfg);
2604
2605 AssertPtr(pSink->pMixSink);
2606 LogFlowFunc(("Sink=%s, Mixer control=%s\n", pSink->pMixSink->pszName, PDMAudioMixerCtlGetName(enmMixerCtl)));
2607 }
2608 else
2609 rc = VERR_NOT_FOUND;
2610
2611 LogFlowFuncLeaveRC(rc);
2612 return rc;
2613}
2614
2615/**
2616 * @interface_method_impl{HDACODECR3,pfnCbMixerRemoveStream}
2617 */
2618static DECLCALLBACK(int) hdaR3MixerRemoveStream(PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl, bool fImmediate)
2619{
2620 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
2621 int rc;
2622
2623 PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThisCC, enmMixerCtl);
2624 if (pSink)
2625 {
2626 PHDADRIVER pDrv;
2627 RTListForEach(&pThisCC->lstDrv, pDrv, HDADRIVER, Node)
2628 {
2629 PAUDMIXSTREAM pMixStream = NULL;
2630 switch (enmMixerCtl)
2631 {
2632 /*
2633 * Input.
2634 */
2635 case PDMAUDIOMIXERCTL_LINE_IN:
2636 pMixStream = pDrv->LineIn.pMixStrm;
2637 pDrv->LineIn.pMixStrm = NULL;
2638 break;
2639# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2640 case PDMAUDIOMIXERCTL_MIC_IN:
2641 pMixStream = pDrv->MicIn.pMixStrm;
2642 pDrv->MicIn.pMixStrm = NULL;
2643 break;
2644# endif
2645 /*
2646 * Output.
2647 */
2648 case PDMAUDIOMIXERCTL_FRONT:
2649 pMixStream = pDrv->Front.pMixStrm;
2650 pDrv->Front.pMixStrm = NULL;
2651 break;
2652# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2653 case PDMAUDIOMIXERCTL_CENTER_LFE:
2654 pMixStream = pDrv->CenterLFE.pMixStrm;
2655 pDrv->CenterLFE.pMixStrm = NULL;
2656 break;
2657 case PDMAUDIOMIXERCTL_REAR:
2658 pMixStream = pDrv->Rear.pMixStrm;
2659 pDrv->Rear.pMixStrm = NULL;
2660 break;
2661# endif
2662 default:
2663 AssertMsgFailed(("Mixer control %d not implemented\n", enmMixerCtl));
2664 break;
2665 }
2666
2667 if (pMixStream)
2668 {
2669 AudioMixerSinkRemoveStream(pSink->pMixSink, pMixStream);
2670 AudioMixerStreamDestroy(pMixStream, pDevIns, fImmediate);
2671
2672 pMixStream = NULL;
2673 }
2674 }
2675
2676 AudioMixerSinkRemoveAllStreams(pSink->pMixSink);
2677 rc = VINF_SUCCESS;
2678 }
2679 else
2680 rc = VERR_NOT_FOUND;
2681
2682 LogFunc(("Mixer control=%s, rc=%Rrc\n", PDMAudioMixerCtlGetName(enmMixerCtl), rc));
2683 return rc;
2684}
2685
2686/**
2687 * @interface_method_impl{HDACODECR3,pfnCbMixerControl}
2688 *
2689 * @note Is also called directly by the DevHDA code.
2690 */
2691static DECLCALLBACK(int) hdaR3MixerControl(PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel)
2692{
2693 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
2694 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
2695 LogFunc(("enmMixerCtl=%s, uSD=%RU8, uChannel=%RU8\n", PDMAudioMixerCtlGetName(enmMixerCtl), uSD, uChannel));
2696
2697 if (uSD == 0) /* Stream number 0 is reserved. */
2698 {
2699 Log2Func(("Invalid SDn (%RU8) number for mixer control '%s', ignoring\n", uSD, PDMAudioMixerCtlGetName(enmMixerCtl)));
2700 return VINF_SUCCESS;
2701 }
2702 /* uChannel is optional. */
2703
2704 /* SDn0 starts as 1. */
2705 Assert(uSD);
2706 uSD--;
2707
2708# ifndef VBOX_WITH_AUDIO_HDA_MIC_IN
2709 /* Only SDI0 (Line-In) is supported. */
2710 if ( hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN
2711 && uSD >= 1)
2712 {
2713 LogRel2(("HDA: Dedicated Mic-In support not imlpemented / built-in (stream #%RU8), using Line-In (stream #0) instead\n", uSD));
2714 uSD = 0;
2715 }
2716# endif
2717
2718 int rc = VINF_SUCCESS;
2719
2720 PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThisCC, enmMixerCtl);
2721 if (pSink)
2722 {
2723 AssertPtr(pSink->pMixSink);
2724
2725 /* If this an output stream, determine the correct SD#. */
2726 if ( uSD < HDA_MAX_SDI
2727 && AudioMixerSinkGetDir(pSink->pMixSink) == PDMAUDIODIR_OUT)
2728 uSD += HDA_MAX_SDI;
2729
2730 /* Make 100% sure we got a good stream number before continuing. */
2731 AssertLogRelReturn(uSD < RT_ELEMENTS(pThisCC->aStreams), VERR_NOT_IMPLEMENTED);
2732
2733 /* Detach the existing stream from the sink. */
2734 PHDASTREAM const pOldStreamShared = pSink->pStreamShared;
2735 PHDASTREAMR3 const pOldStreamR3 = pSink->pStreamR3;
2736 if ( pOldStreamShared
2737 && pOldStreamR3
2738 && ( pOldStreamShared->u8SD != uSD
2739 || pOldStreamShared->u8Channel != uChannel)
2740 )
2741 {
2742 LogFunc(("Sink '%s' was assigned to stream #%RU8 (channel %RU8) before\n",
2743 pSink->pMixSink->pszName, pOldStreamShared->u8SD, pOldStreamShared->u8Channel));
2744 Assert(PDMCritSectIsOwner(&pThis->CritSect));
2745
2746 /* Only disable the stream if the stream descriptor # has changed. */
2747 if (pOldStreamShared->u8SD != uSD)
2748 hdaR3StreamEnable(pThis, pOldStreamShared, pOldStreamR3, false /*fEnable*/);
2749
2750 if (pOldStreamR3->State.pAioRegSink)
2751 {
2752 AudioMixerSinkRemoveUpdateJob(pOldStreamR3->State.pAioRegSink, hdaR3StreamUpdateAsyncIoJob, pOldStreamR3);
2753 pOldStreamR3->State.pAioRegSink = NULL;
2754 }
2755
2756 pOldStreamR3->pMixSink = NULL;
2757
2758
2759 pSink->pStreamShared = NULL;
2760 pSink->pStreamR3 = NULL;
2761 }
2762
2763 /* Attach the new stream to the sink.
2764 * Enabling the stream will be done by the guest via a separate SDnCTL call then. */
2765 if (pSink->pStreamShared == NULL)
2766 {
2767 LogRel2(("HDA: Setting sink '%s' to stream #%RU8 (channel %RU8), mixer control=%s\n",
2768 pSink->pMixSink->pszName, uSD, uChannel, PDMAudioMixerCtlGetName(enmMixerCtl)));
2769
2770 PHDASTREAMR3 pStreamR3 = &pThisCC->aStreams[uSD];
2771 PHDASTREAM pStreamShared = &pThis->aStreams[uSD];
2772 Assert(PDMCritSectIsOwner(&pThis->CritSect));
2773
2774 pSink->pStreamR3 = pStreamR3;
2775 pSink->pStreamShared = pStreamShared;
2776
2777 pStreamShared->u8Channel = uChannel;
2778 pStreamR3->pMixSink = pSink;
2779
2780 rc = VINF_SUCCESS;
2781 }
2782 }
2783 else
2784 rc = VERR_NOT_FOUND;
2785
2786 if (RT_FAILURE(rc))
2787 LogRel(("HDA: Converter control for stream #%RU8 (channel %RU8) / mixer control '%s' failed with %Rrc, skipping\n",
2788 uSD, uChannel, PDMAudioMixerCtlGetName(enmMixerCtl), rc));
2789
2790 LogFlowFuncLeaveRC(rc);
2791 return rc;
2792}
2793
2794/**
2795 * @interface_method_impl{HDACODECR3,pfnCbMixerSetVolume}
2796 */
2797static DECLCALLBACK(int) hdaR3MixerSetVolume(PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOVOLUME pVol)
2798{
2799 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
2800 int rc;
2801
2802 PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThisCC, enmMixerCtl);
2803 if ( pSink
2804 && pSink->pMixSink)
2805 {
2806 LogRel2(("HDA: Setting volume for mixer sink '%s' to fMuted=%RTbool auChannels=%.*Rhxs\n",
2807 pSink->pMixSink->pszName, pVol->fMuted, sizeof(pVol->auChannels), pVol->auChannels));
2808
2809 /* Set the volume.
2810 * We assume that the codec already converted it to the correct range. */
2811 rc = AudioMixerSinkSetVolume(pSink->pMixSink, pVol);
2812 }
2813 else
2814 rc = VERR_NOT_FOUND;
2815
2816 LogFlowFuncLeaveRC(rc);
2817 return rc;
2818}
2819
2820/**
2821 * @callback_method_impl{FNTMTIMERDEV, Main routine for the stream's timer.}
2822 */
2823static DECLCALLBACK(void) hdaR3Timer(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)
2824{
2825 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
2826 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
2827 uintptr_t idxStream = (uintptr_t)pvUser;
2828 AssertReturnVoid(idxStream < RT_ELEMENTS(pThis->aStreams));
2829 PHDASTREAM pStreamShared = &pThis->aStreams[idxStream];
2830 PHDASTREAMR3 pStreamR3 = &pThisCC->aStreams[idxStream];
2831 Assert(hTimer == pStreamShared->hTimer);
2832
2833 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
2834 Assert(PDMDevHlpTimerIsLockOwner(pDevIns, hTimer));
2835
2836 RT_NOREF(hTimer);
2837
2838 hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
2839}
2840
2841/**
2842 * Soft reset of the device triggered via GCTL.
2843 *
2844 * @param pDevIns The device instance.
2845 * @param pThis The shared HDA device state.
2846 * @param pThisCC The ring-3 HDA device state.
2847 */
2848static void hdaR3GCTLReset(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC)
2849{
2850 LogFlowFuncEnter();
2851 Assert(PDMCritSectIsOwner(&pThis->CritSect));
2852
2853 /*
2854 * Make sure all streams have stopped as these have both timers and
2855 * asynchronous worker threads that would race us if we delay this work.
2856 */
2857 for (size_t idxStream = 0; idxStream < RT_ELEMENTS(pThis->aStreams); idxStream++)
2858 {
2859 PHDASTREAM const pStreamShared = &pThis->aStreams[idxStream];
2860 PHDASTREAMR3 const pStreamR3 = &pThisCC->aStreams[idxStream];
2861 PAUDMIXSINK const pMixSink = pStreamR3->pMixSink ? pStreamR3->pMixSink->pMixSink : NULL;
2862 if (pMixSink)
2863 AudioMixerSinkLock(pMixSink);
2864
2865 /* We're doing this unconditionally, hope that's not problematic in any way... */
2866 int rc = hdaR3StreamEnable(pThis, pStreamShared, &pThisCC->aStreams[idxStream], false /* fEnable */);
2867 AssertLogRelMsg(RT_SUCCESS(rc) && !pStreamShared->State.fRunning,
2868 ("Disabling stream #%u failed: %Rrc, fRunning=%d\n", idxStream, rc, pStreamShared->State.fRunning));
2869 pStreamShared->State.fRunning = false;
2870
2871 hdaR3StreamReset(pThis, pThisCC, pStreamShared, &pThisCC->aStreams[idxStream], (uint8_t)idxStream);
2872
2873 if (pMixSink) /* (FYI. pMixSink might not be what pStreamR3->pMixSink->pMixSink points at any longer) */
2874 AudioMixerSinkUnlock(pMixSink);
2875 }
2876
2877 /*
2878 * Reset registers.
2879 */
2880 HDA_REG(pThis, GCAP) = HDA_MAKE_GCAP(HDA_MAX_SDO, HDA_MAX_SDI, 0, 0, 1); /* see 6.2.1 */
2881 HDA_REG(pThis, VMIN) = 0x00; /* see 6.2.2 */
2882 HDA_REG(pThis, VMAJ) = 0x01; /* see 6.2.3 */
2883 HDA_REG(pThis, OUTPAY) = 0x003C; /* see 6.2.4 */
2884 HDA_REG(pThis, INPAY) = 0x001D; /* see 6.2.5 */
2885 HDA_REG(pThis, CORBSIZE) = 0x42; /* Up to 256 CORB entries see 6.2.1 */
2886 HDA_REG(pThis, RIRBSIZE) = 0x42; /* Up to 256 RIRB entries see 6.2.1 */
2887 HDA_REG(pThis, CORBRP) = 0x0;
2888 HDA_REG(pThis, CORBWP) = 0x0;
2889 HDA_REG(pThis, RIRBWP) = 0x0;
2890 /* Some guests (like Haiku) don't set RINTCNT explicitly but expect an interrupt after each
2891 * RIRB response -- so initialize RINTCNT to 1 by default. */
2892 HDA_REG(pThis, RINTCNT) = 0x1;
2893
2894 /*
2895 * Stop any audio currently playing and/or recording.
2896 */
2897 pThisCC->SinkFront.pStreamShared = NULL;
2898 pThisCC->SinkFront.pStreamR3 = NULL;
2899 if (pThisCC->SinkFront.pMixSink)
2900 AudioMixerSinkReset(pThisCC->SinkFront.pMixSink);
2901# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2902 pThisCC->SinkMicIn.pStreamShared = NULL;
2903 pThisCC->SinkMicIn.pStreamR3 = NULL;
2904 if (pThisCC->SinkMicIn.pMixSink)
2905 AudioMixerSinkReset(pThisCC->SinkMicIn.pMixSink);
2906# endif
2907 pThisCC->SinkLineIn.pStreamShared = NULL;
2908 pThisCC->SinkLineIn.pStreamR3 = NULL;
2909 if (pThisCC->SinkLineIn.pMixSink)
2910 AudioMixerSinkReset(pThisCC->SinkLineIn.pMixSink);
2911# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2912 pThisCC->SinkCenterLFE = NULL;
2913 if (pThisCC->SinkCenterLFE.pMixSink)
2914 AudioMixerSinkReset(pThisCC->SinkCenterLFE.pMixSink);
2915 pThisCC->SinkRear.pStreamShared = NULL;
2916 pThisCC->SinkRear.pStreamR3 = NULL;
2917 if (pThisCC->SinkRear.pMixSink)
2918 AudioMixerSinkReset(pThisCC->SinkRear.pMixSink);
2919# endif
2920
2921 /*
2922 * Reset the codec.
2923 */
2924 hdaCodecReset(&pThisCC->Codec);
2925
2926 /*
2927 * Set some sensible defaults for which HDA sinks
2928 * are connected to which stream number.
2929 *
2930 * We use SD0 for input and SD4 for output by default.
2931 * These stream numbers can be changed by the guest dynamically lateron.
2932 */
2933 ASMCompilerBarrier(); /* paranoia */
2934# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2935 hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_MIC_IN , 1 /* SD0 */, 0 /* Channel */);
2936# endif
2937 hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_LINE_IN , 1 /* SD0 */, 0 /* Channel */);
2938
2939 hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_FRONT , 5 /* SD4 */, 0 /* Channel */);
2940# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2941 hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_CENTER_LFE, 5 /* SD4 */, 0 /* Channel */);
2942 hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_REAR , 5 /* SD4 */, 0 /* Channel */);
2943# endif
2944 ASMCompilerBarrier(); /* paranoia */
2945
2946 /* Reset CORB. */
2947 pThis->cbCorbBuf = HDA_CORB_SIZE * HDA_CORB_ELEMENT_SIZE;
2948 RT_ZERO(pThis->au32CorbBuf);
2949
2950 /* Reset RIRB. */
2951 pThis->cbRirbBuf = HDA_RIRB_SIZE * HDA_RIRB_ELEMENT_SIZE;
2952 RT_ZERO(pThis->au64RirbBuf);
2953
2954 /* Clear our internal response interrupt counter. */
2955 pThis->u16RespIntCnt = 0;
2956
2957 /* Clear stream tags <-> objects mapping table. */
2958 RT_ZERO(pThisCC->aTags);
2959
2960 /* Emulation of codec "wake up" (HDA spec 5.5.1 and 6.5). */
2961 HDA_REG(pThis, STATESTS) = 0x1;
2962
2963 /* Reset the wall clock. */
2964 pThis->tsWalClkStart = PDMDevHlpTimerGet(pDevIns, pThis->aStreams[0].hTimer);
2965
2966 LogFlowFuncLeave();
2967 LogRel(("HDA: Reset\n"));
2968}
2969
2970#else /* !IN_RING3 */
2971
2972/**
2973 * Checks if a dword read starting with @a idxRegDsc is safe.
2974 *
2975 * We can guarentee it only standard reader callbacks are used.
2976 * @returns true if it will always succeed, false if it may return back to
2977 * ring-3 or we're just not sure.
2978 * @param idxRegDsc The first register descriptor in the DWORD being read.
2979 */
2980DECLINLINE(bool) hdaIsMultiReadSafeInRZ(unsigned idxRegDsc)
2981{
2982 int32_t cbLeft = 4; /* signed on purpose */
2983 do
2984 {
2985 if ( g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadU24
2986 || g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadU16
2987 || g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadU8
2988 || g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadUnimpl)
2989 { /* okay */ }
2990 else
2991 {
2992 Log4(("hdaIsMultiReadSafeInRZ: idxRegDsc=%u %s\n", idxRegDsc, g_aHdaRegMap[idxRegDsc].pszName));
2993 return false;
2994 }
2995
2996 idxRegDsc++;
2997 if (idxRegDsc < RT_ELEMENTS(g_aHdaRegMap))
2998 cbLeft -= g_aHdaRegMap[idxRegDsc].off - g_aHdaRegMap[idxRegDsc - 1].off;
2999 else
3000 break;
3001 } while (cbLeft > 0);
3002 return true;
3003}
3004
3005
3006#endif /* !IN_RING3 */
3007
3008
3009/* MMIO callbacks */
3010
3011/**
3012 * @callback_method_impl{FNIOMMMIONEWREAD, Looks up and calls the appropriate handler.}
3013 *
3014 * @note During implementation, we discovered so-called "forgotten" or "hole"
3015 * registers whose description is not listed in the RPM, datasheet, or
3016 * spec.
3017 */
3018static DECLCALLBACK(VBOXSTRICTRC) hdaMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
3019{
3020 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3021 VBOXSTRICTRC rc;
3022 RT_NOREF_PV(pvUser);
3023 Assert(pThis->uAlignmentCheckMagic == HDASTATE_ALIGNMENT_CHECK_MAGIC);
3024
3025 /*
3026 * Look up and log.
3027 */
3028 int idxRegDsc = hdaRegLookup(off); /* Register descriptor index. */
3029#ifdef LOG_ENABLED
3030 unsigned const cbLog = cb;
3031 uint32_t offRegLog = (uint32_t)off;
3032# ifdef HDA_DEBUG_GUEST_RIP
3033 if (LogIs6Enabled())
3034 {
3035 PVMCPU pVCpu = (PVMCPU)PDMDevHlpGetVMCPU(pDevIns);
3036 Log6Func(("cs:rip=%04x:%016RX64 rflags=%08RX32\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu), CPUMGetGuestEFlags(pVCpu)));
3037 }
3038# endif
3039#endif
3040
3041 Log3Func(("off=%#x cb=%#x\n", offRegLog, cb));
3042 Assert(cb == 4); Assert((off & 3) == 0);
3043
3044 rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VINF_IOM_R3_MMIO_READ);
3045 if (rc == VINF_SUCCESS)
3046 {
3047 if (!(HDA_REG(pThis, GCTL) & HDA_GCTL_CRST) && idxRegDsc != HDA_REG_GCTL)
3048 LogFunc(("Access to registers except GCTL is blocked while resetting\n"));
3049
3050 if (idxRegDsc >= 0)
3051 {
3052 /* ASSUMES gapless DWORD at end of map. */
3053 if (g_aHdaRegMap[idxRegDsc].cb == 4)
3054 {
3055 /*
3056 * Straight forward DWORD access.
3057 */
3058 rc = g_aHdaRegMap[idxRegDsc].pfnRead(pDevIns, pThis, idxRegDsc, (uint32_t *)pv);
3059 Log3Func((" Read %s => %x (%Rrc)\n", g_aHdaRegMap[idxRegDsc].pszName, *(uint32_t *)pv, VBOXSTRICTRC_VAL(rc)));
3060 STAM_COUNTER_INC(&pThis->aStatRegReads[idxRegDsc]);
3061 }
3062#ifndef IN_RING3
3063 else if (!hdaIsMultiReadSafeInRZ(idxRegDsc))
3064
3065 {
3066 STAM_COUNTER_INC(&pThis->aStatRegReadsToR3[idxRegDsc]);
3067 rc = VINF_IOM_R3_MMIO_READ;
3068 }
3069#endif
3070 else
3071 {
3072 /*
3073 * Multi register read (unless there are trailing gaps).
3074 * ASSUMES that only DWORD reads have sideeffects.
3075 */
3076 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegMultiReads));
3077 Log4(("hdaMmioRead: multi read: %#x LB %#x %s\n", off, cb, g_aHdaRegMap[idxRegDsc].pszName));
3078 uint32_t u32Value = 0;
3079 unsigned cbLeft = 4;
3080 do
3081 {
3082 uint32_t const cbReg = g_aHdaRegMap[idxRegDsc].cb;
3083 uint32_t u32Tmp = 0;
3084
3085 rc = g_aHdaRegMap[idxRegDsc].pfnRead(pDevIns, pThis, idxRegDsc, &u32Tmp);
3086 Log4Func((" Read %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxRegDsc].pszName, cbReg, u32Tmp, VBOXSTRICTRC_VAL(rc)));
3087 STAM_COUNTER_INC(&pThis->aStatRegReads[idxRegDsc]);
3088#ifdef IN_RING3
3089 if (rc != VINF_SUCCESS)
3090 break;
3091#else
3092 AssertMsgBreak(rc == VINF_SUCCESS, ("rc=%Rrc - impossible, we sanitized the readers!\n", VBOXSTRICTRC_VAL(rc)));
3093#endif
3094 u32Value |= (u32Tmp & g_afMasks[cbReg]) << ((4 - cbLeft) * 8);
3095
3096 cbLeft -= cbReg;
3097 off += cbReg;
3098 idxRegDsc++;
3099 } while (cbLeft > 0 && g_aHdaRegMap[idxRegDsc].off == off);
3100
3101 if (rc == VINF_SUCCESS)
3102 *(uint32_t *)pv = u32Value;
3103 else
3104 Assert(!IOM_SUCCESS(rc));
3105 }
3106 }
3107 else
3108 {
3109 LogRel(("HDA: Invalid read access @0x%x (bytes=%u)\n", (uint32_t)off, cb));
3110 Log3Func((" Hole at %x is accessed for read\n", offRegLog));
3111 STAM_COUNTER_INC(&pThis->StatRegUnknownReads);
3112 rc = VINF_IOM_MMIO_UNUSED_FF;
3113 }
3114
3115 DEVHDA_UNLOCK(pDevIns, pThis);
3116
3117 /*
3118 * Log the outcome.
3119 */
3120#ifdef LOG_ENABLED
3121 if (cbLog == 4)
3122 Log3Func((" Returning @%#05x -> %#010x %Rrc\n", offRegLog, *(uint32_t *)pv, VBOXSTRICTRC_VAL(rc)));
3123 else if (cbLog == 2)
3124 Log3Func((" Returning @%#05x -> %#06x %Rrc\n", offRegLog, *(uint16_t *)pv, VBOXSTRICTRC_VAL(rc)));
3125 else if (cbLog == 1)
3126 Log3Func((" Returning @%#05x -> %#04x %Rrc\n", offRegLog, *(uint8_t *)pv, VBOXSTRICTRC_VAL(rc)));
3127#endif
3128 }
3129 else
3130 {
3131 if (idxRegDsc >= 0)
3132 STAM_COUNTER_INC(&pThis->aStatRegReadsToR3[idxRegDsc]);
3133 }
3134 return rc;
3135}
3136
3137
3138DECLINLINE(VBOXSTRICTRC) hdaWriteReg(PPDMDEVINS pDevIns, PHDASTATE pThis, int idxRegDsc, uint32_t u32Value, char const *pszLog)
3139{
3140 if ( (HDA_REG(pThis, GCTL) & HDA_GCTL_CRST)
3141 || idxRegDsc == HDA_REG_GCTL)
3142 { /* likely */ }
3143 else
3144 {
3145 Log(("hdaWriteReg: Warning: Access to %s is blocked while controller is in reset mode\n", g_aHdaRegMap[idxRegDsc].pszName));
3146#if defined(IN_RING3) || defined(LOG_ENABLED)
3147 LogRel2(("HDA: Warning: Access to register %s is blocked while controller is in reset mode\n",
3148 g_aHdaRegMap[idxRegDsc].pszName));
3149#endif
3150 STAM_COUNTER_INC(&pThis->StatRegWritesBlockedByReset);
3151 return VINF_SUCCESS;
3152 }
3153
3154 /*
3155 * Handle RD (register description) flags.
3156 */
3157
3158 /* For SDI / SDO: Check if writes to those registers are allowed while SDCTL's RUN bit is set. */
3159 if (idxRegDsc >= HDA_NUM_GENERAL_REGS)
3160 {
3161 /*
3162 * Some OSes (like Win 10 AU) violate the spec by writing stuff to registers which are not supposed to be be touched
3163 * while SDCTL's RUN bit is set. So just ignore those values.
3164 */
3165 const uint32_t uSDCTL = HDA_STREAM_REG(pThis, CTL, HDA_SD_NUM_FROM_REG(pThis, CTL, idxRegDsc));
3166 if ( !(uSDCTL & HDA_SDCTL_RUN)
3167 || (g_aHdaRegMap[idxRegDsc].fFlags & HDA_RD_F_SD_WRITE_RUN))
3168 { /* likely */ }
3169 else
3170 {
3171 Log(("hdaWriteReg: Warning: Access to %s is blocked! %R[sdctl]\n", g_aHdaRegMap[idxRegDsc].pszName, uSDCTL));
3172#if defined(IN_RING3) || defined(LOG_ENABLED)
3173 LogRel2(("HDA: Warning: Access to register %s is blocked while the stream's RUN bit is set\n",
3174 g_aHdaRegMap[idxRegDsc].pszName));
3175#endif
3176 STAM_COUNTER_INC(&pThis->StatRegWritesBlockedByRun);
3177 return VINF_SUCCESS;
3178 }
3179 }
3180
3181#ifdef LOG_ENABLED
3182 uint32_t const idxRegMem = g_aHdaRegMap[idxRegDsc].idxReg;
3183 uint32_t const u32OldValue = pThis->au32Regs[idxRegMem];
3184#endif
3185 VBOXSTRICTRC rc = g_aHdaRegMap[idxRegDsc].pfnWrite(pDevIns, pThis, idxRegDsc, u32Value);
3186 Log3Func(("Written value %#x to %s[%d byte]; %x => %x%s, rc=%d\n", u32Value, g_aHdaRegMap[idxRegDsc].pszName,
3187 g_aHdaRegMap[idxRegDsc].cb, u32OldValue, pThis->au32Regs[idxRegMem], pszLog, VBOXSTRICTRC_VAL(rc)));
3188#ifndef IN_RING3
3189 if (rc == VINF_IOM_R3_MMIO_WRITE)
3190 STAM_COUNTER_INC(&pThis->aStatRegWritesToR3[idxRegDsc]);
3191 else
3192#endif
3193 STAM_COUNTER_INC(&pThis->aStatRegWrites[idxRegDsc]);
3194
3195 RT_NOREF(pszLog);
3196 return rc;
3197}
3198
3199
3200/**
3201 * @callback_method_impl{FNIOMMMIONEWWRITE,
3202 * Looks up and calls the appropriate handler.}
3203 */
3204static DECLCALLBACK(VBOXSTRICTRC) hdaMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
3205{
3206 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3207 RT_NOREF_PV(pvUser);
3208 Assert(pThis->uAlignmentCheckMagic == HDASTATE_ALIGNMENT_CHECK_MAGIC);
3209
3210 /*
3211 * Look up and log the access.
3212 */
3213 int idxRegDsc = hdaRegLookup(off);
3214#if defined(IN_RING3) || defined(LOG_ENABLED)
3215 uint32_t idxRegMem = idxRegDsc != -1 ? g_aHdaRegMap[idxRegDsc].idxReg : UINT32_MAX;
3216#endif
3217 uint64_t u64Value;
3218 if (cb == 4) u64Value = *(uint32_t const *)pv;
3219 else if (cb == 2) u64Value = *(uint16_t const *)pv;
3220 else if (cb == 1) u64Value = *(uint8_t const *)pv;
3221 else if (cb == 8) u64Value = *(uint64_t const *)pv;
3222 else
3223 ASSERT_GUEST_MSG_FAILED_RETURN(("cb=%u %.*Rhxs\n", cb, cb, pv),
3224 PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "odd write size: off=%RGp cb=%u\n", off, cb));
3225
3226 /*
3227 * The behavior of accesses that aren't aligned on natural boundraries is
3228 * undefined. Just reject them outright.
3229 */
3230 ASSERT_GUEST_MSG_RETURN((off & (cb - 1)) == 0, ("off=%RGp cb=%u %.*Rhxs\n", off, cb, cb, pv),
3231 PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "misaligned write access: off=%RGp cb=%u\n", off, cb));
3232
3233#ifdef LOG_ENABLED
3234 uint32_t const u32LogOldValue = idxRegDsc >= 0 ? pThis->au32Regs[idxRegMem] : UINT32_MAX;
3235# ifdef HDA_DEBUG_GUEST_RIP
3236 if (LogIs6Enabled())
3237 {
3238 PVMCPU pVCpu = (PVMCPU)PDMDevHlpGetVMCPU(pDevIns);
3239 Log6Func(("cs:rip=%04x:%016RX64 rflags=%08RX32\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu), CPUMGetGuestEFlags(pVCpu)));
3240 }
3241# endif
3242#endif
3243
3244 /*
3245 * Try for a direct hit first.
3246 */
3247 VBOXSTRICTRC rc;
3248 if (idxRegDsc >= 0 && g_aHdaRegMap[idxRegDsc].cb == cb)
3249 {
3250 DEVHDA_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
3251
3252 Log3Func(("@%#05x u%u=%#0*RX64 %s\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, g_aHdaRegMap[idxRegDsc].pszName));
3253 rc = hdaWriteReg(pDevIns, pThis, idxRegDsc, u64Value, "");
3254 Log3Func((" %#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
3255
3256 DEVHDA_UNLOCK(pDevIns, pThis);
3257 }
3258 /*
3259 * Sub-register access. Supply missing bits as needed.
3260 */
3261 else if ( idxRegDsc >= 0
3262 && cb < g_aHdaRegMap[idxRegDsc].cb)
3263 {
3264 DEVHDA_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
3265
3266 u64Value |= pThis->au32Regs[g_aHdaRegMap[idxRegDsc].idxReg]
3267 & g_afMasks[g_aHdaRegMap[idxRegDsc].cb]
3268 & ~g_afMasks[cb];
3269 Log4Func(("@%#05x u%u=%#0*RX64 cb=%#x cbReg=%x %s\n"
3270 "hdaMmioWrite: Supplying missing bits (%#x): %#llx -> %#llx ...\n",
3271 (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, cb, g_aHdaRegMap[idxRegDsc].cb, g_aHdaRegMap[idxRegDsc].pszName,
3272 g_afMasks[g_aHdaRegMap[idxRegDsc].cb] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
3273 rc = hdaWriteReg(pDevIns, pThis, idxRegDsc, u64Value, "");
3274 Log4Func((" %#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
3275 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegSubWrite));
3276
3277 DEVHDA_UNLOCK(pDevIns, pThis);
3278 }
3279 /*
3280 * Partial or multiple register access, loop thru the requested memory.
3281 */
3282 else
3283 {
3284#ifdef IN_RING3
3285 DEVHDA_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
3286
3287 if (idxRegDsc == -1)
3288 Log4Func(("@%#05x u32=%#010x cb=%d\n", (uint32_t)off, *(uint32_t const *)pv, cb));
3289 else if (g_aHdaRegMap[idxRegDsc].cb == cb)
3290 Log4Func(("@%#05x u%u=%#0*RX64 %s\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, g_aHdaRegMap[idxRegDsc].pszName));
3291 else
3292 Log4Func(("@%#05x u%u=%#0*RX64 %s - mismatch cbReg=%u\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value,
3293 g_aHdaRegMap[idxRegDsc].pszName, g_aHdaRegMap[idxRegDsc].cb));
3294
3295 /*
3296 * If it's an access beyond the start of the register, shift the input
3297 * value and fill in missing bits. Natural alignment rules means we
3298 * will only see 1 or 2 byte accesses of this kind, so no risk of
3299 * shifting out input values.
3300 */
3301 if (idxRegDsc < 0)
3302 {
3303 idxRegDsc = hdaR3RegLookupWithin(off);
3304 if (idxRegDsc != -1)
3305 {
3306 uint32_t const cbBefore = (uint32_t)off - g_aHdaRegMap[idxRegDsc].off;
3307 Assert(cbBefore > 0 && cbBefore < 4);
3308 off -= cbBefore;
3309 idxRegMem = g_aHdaRegMap[idxRegDsc].idxReg;
3310 u64Value <<= cbBefore * 8;
3311 u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbBefore];
3312 Log4Func((" Within register, supplied %u leading bits: %#llx -> %#llx ...\n",
3313 cbBefore * 8, ~(uint64_t)g_afMasks[cbBefore] & u64Value, u64Value));
3314 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegMultiWrites));
3315 }
3316 else
3317 STAM_COUNTER_INC(&pThis->StatRegUnknownWrites);
3318 }
3319 else
3320 {
3321 Log4(("hdaMmioWrite: multi write: %s\n", g_aHdaRegMap[idxRegDsc].pszName));
3322 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegMultiWrites));
3323 }
3324
3325 /* Loop thru the write area, it may cover multiple registers. */
3326 rc = VINF_SUCCESS;
3327 for (;;)
3328 {
3329 uint32_t cbReg;
3330 if (idxRegDsc >= 0)
3331 {
3332 idxRegMem = g_aHdaRegMap[idxRegDsc].idxReg;
3333 cbReg = g_aHdaRegMap[idxRegDsc].cb;
3334 if (cb < cbReg)
3335 {
3336 u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbReg] & ~g_afMasks[cb];
3337 Log4Func((" Supplying missing bits (%#x): %#llx -> %#llx ...\n",
3338 g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
3339 }
3340# ifdef LOG_ENABLED
3341 uint32_t uLogOldVal = pThis->au32Regs[idxRegMem];
3342# endif
3343 rc = hdaWriteReg(pDevIns, pThis, idxRegDsc, u64Value & g_afMasks[cbReg], "*");
3344 Log4Func((" %#x -> %#x\n", uLogOldVal, pThis->au32Regs[idxRegMem]));
3345 }
3346 else
3347 {
3348 LogRel(("HDA: Invalid write access @0x%x\n", (uint32_t)off));
3349 cbReg = 1;
3350 }
3351 if (rc != VINF_SUCCESS)
3352 break;
3353 if (cbReg >= cb)
3354 break;
3355
3356 /* Advance. */
3357 off += cbReg;
3358 cb -= cbReg;
3359 u64Value >>= cbReg * 8;
3360 if (idxRegDsc == -1)
3361 idxRegDsc = hdaRegLookup(off);
3362 else
3363 {
3364 idxRegDsc++;
3365 if ( (unsigned)idxRegDsc >= RT_ELEMENTS(g_aHdaRegMap)
3366 || g_aHdaRegMap[idxRegDsc].off != off)
3367 idxRegDsc = -1;
3368 }
3369 }
3370
3371 DEVHDA_UNLOCK(pDevIns, pThis);
3372
3373#else /* !IN_RING3 */
3374 /* Take the simple way out. */
3375 rc = VINF_IOM_R3_MMIO_WRITE;
3376#endif /* !IN_RING3 */
3377 }
3378
3379 return rc;
3380}
3381
3382#ifdef IN_RING3
3383
3384
3385/*********************************************************************************************************************************
3386* Saved state *
3387*********************************************************************************************************************************/
3388
3389/**
3390 * @callback_method_impl{FNSSMFIELDGETPUT,
3391 * Version 6 saves the IOC flag in HDABDLEDESC::fFlags as a bool}
3392 */
3393static DECLCALLBACK(int)
3394hdaR3GetPutTrans_HDABDLEDESC_fFlags_6(PSSMHANDLE pSSM, const struct SSMFIELD *pField, void *pvStruct,
3395 uint32_t fFlags, bool fGetOrPut, void *pvUser)
3396{
3397 PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
3398 RT_NOREF(pSSM, pField, pvStruct, fFlags);
3399 AssertReturn(fGetOrPut, VERR_INTERNAL_ERROR_4);
3400 bool fIoc;
3401 int rc = pDevIns->pHlpR3->pfnSSMGetBool(pSSM, &fIoc);
3402 if (RT_SUCCESS(rc))
3403 {
3404 PHDABDLEDESC pDesc = (PHDABDLEDESC)pvStruct;
3405 pDesc->fFlags = fIoc ? HDA_BDLE_F_IOC : 0;
3406 }
3407 return rc;
3408}
3409
3410
3411/**
3412 * @callback_method_impl{FNSSMFIELDGETPUT,
3413 * Versions 1 thru 4 save the IOC flag in HDASTREAMSTATE::DescfFlags as a bool}
3414 */
3415static DECLCALLBACK(int)
3416hdaR3GetPutTrans_HDABDLE_Desc_fFlags_1thru4(PSSMHANDLE pSSM, const struct SSMFIELD *pField, void *pvStruct,
3417 uint32_t fFlags, bool fGetOrPut, void *pvUser)
3418{
3419 PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
3420 RT_NOREF(pSSM, pField, pvStruct, fFlags);
3421 AssertReturn(fGetOrPut, VERR_INTERNAL_ERROR_4);
3422 bool fIoc;
3423 int rc = pDevIns->pHlpR3->pfnSSMGetBool(pSSM, &fIoc);
3424 if (RT_SUCCESS(rc))
3425 {
3426 HDABDLELEGACY *pState = (HDABDLELEGACY *)pvStruct;
3427 pState->Desc.fFlags = fIoc ? HDA_BDLE_F_IOC : 0;
3428 }
3429 return rc;
3430}
3431
3432
3433static int hdaR3SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)
3434{
3435 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3436# ifdef LOG_ENABLED
3437 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3438# endif
3439
3440 Log2Func(("[SD%RU8]\n", pStreamShared->u8SD));
3441
3442 /* Save stream ID. */
3443 Assert(pStreamShared->u8SD < HDA_MAX_STREAMS);
3444 int rc = pHlp->pfnSSMPutU8(pSSM, pStreamShared->u8SD);
3445 AssertRCReturn(rc, rc);
3446
3447 rc = pHlp->pfnSSMPutStructEx(pSSM, &pStreamShared->State, sizeof(pStreamShared->State),
3448 0 /*fFlags*/, g_aSSMStreamStateFields7, NULL);
3449 AssertRCReturn(rc, rc);
3450
3451 AssertCompile(sizeof(pStreamShared->State.idxCurBdle) == sizeof(uint8_t) && RT_ELEMENTS(pStreamShared->State.aBdl) == 256);
3452 HDABDLEDESC TmpDesc = *(HDABDLEDESC *)&pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle];
3453 rc = pHlp->pfnSSMPutStructEx(pSSM, &TmpDesc, sizeof(TmpDesc), 0 /*fFlags*/, g_aSSMBDLEDescFields7, NULL);
3454 AssertRCReturn(rc, rc);
3455
3456 HDABDLESTATELEGACY TmpState = { pStreamShared->State.idxCurBdle, 0, pStreamShared->State.offCurBdle, 0 };
3457 rc = pHlp->pfnSSMPutStructEx(pSSM, &TmpState, sizeof(TmpState), 0 /*fFlags*/, g_aSSMBDLEStateFields7, NULL);
3458 AssertRCReturn(rc, rc);
3459
3460 PAUDMIXSINK pSink = NULL;
3461 uint32_t cbCircBuf = 0;
3462 uint32_t cbCircBufUsed = 0;
3463 if (pStreamR3->State.pCircBuf)
3464 {
3465 cbCircBuf = (uint32_t)RTCircBufSize(pStreamR3->State.pCircBuf);
3466
3467 /* We take the AIO lock here and releases it after saving the buffer,
3468 otherwise the AIO thread could race us reading out the buffer data. */
3469 pSink = pStreamR3->pMixSink ? pStreamR3->pMixSink->pMixSink : NULL;
3470 if ( !pSink
3471 || RT_SUCCESS(AudioMixerSinkTryLock(pSink)))
3472 {
3473 cbCircBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
3474 if (cbCircBufUsed == 0 && pSink)
3475 AudioMixerSinkUnlock(pSink);
3476 }
3477 }
3478
3479 pHlp->pfnSSMPutU32(pSSM, cbCircBuf);
3480 rc = pHlp->pfnSSMPutU32(pSSM, cbCircBufUsed);
3481
3482 if (cbCircBufUsed > 0)
3483 {
3484 /* HACK ALERT! We cannot remove data from the buffer (live snapshot),
3485 we use RTCircBufOffsetRead and RTCircBufAcquireReadBlock
3486 creatively to get at the other buffer segment in case
3487 of a wraparound. */
3488 size_t const offBuf = RTCircBufOffsetRead(pStreamR3->State.pCircBuf);
3489 void *pvBuf = NULL;
3490 size_t cbBuf = 0;
3491 RTCircBufAcquireReadBlock(pStreamR3->State.pCircBuf, cbCircBufUsed, &pvBuf, &cbBuf);
3492 Assert(cbBuf);
3493 rc = pHlp->pfnSSMPutMem(pSSM, pvBuf, cbBuf);
3494 if (cbBuf < cbCircBufUsed)
3495 rc = pHlp->pfnSSMPutMem(pSSM, (uint8_t *)pvBuf - offBuf, cbCircBufUsed - cbBuf);
3496 RTCircBufReleaseReadBlock(pStreamR3->State.pCircBuf, 0 /* Don't advance read pointer! */);
3497
3498 if (pSink)
3499 AudioMixerSinkUnlock(pSink);
3500 }
3501
3502 Log2Func(("[SD%RU8] LPIB=%RU32, CBL=%RU32, LVI=%RU32\n", pStreamR3->u8SD, HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD),
3503 HDA_STREAM_REG(pThis, CBL, pStreamShared->u8SD), HDA_STREAM_REG(pThis, LVI, pStreamShared->u8SD)));
3504
3505#ifdef LOG_ENABLED
3506 hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
3507#endif
3508
3509 return rc;
3510}
3511
3512/**
3513 * @callback_method_impl{FNSSMDEVSAVEEXEC}
3514 */
3515static DECLCALLBACK(int) hdaR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
3516{
3517 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3518 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
3519 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3520
3521 /* Save Codec nodes states. */
3522 hdaCodecSaveState(pDevIns, &pThisCC->Codec, pSSM);
3523
3524 /* Save MMIO registers. */
3525 pHlp->pfnSSMPutU32(pSSM, RT_ELEMENTS(pThis->au32Regs));
3526 pHlp->pfnSSMPutMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
3527
3528 /* Save controller-specifc internals. */
3529 pHlp->pfnSSMPutU64(pSSM, pThis->tsWalClkStart);
3530 pHlp->pfnSSMPutU8(pSSM, pThis->u8IRQL);
3531
3532 /* Save number of streams. */
3533 pHlp->pfnSSMPutU32(pSSM, HDA_MAX_STREAMS);
3534
3535 /* Save stream states. */
3536 for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
3537 {
3538 int rc = hdaR3SaveStream(pDevIns, pSSM, &pThis->aStreams[i], &pThisCC->aStreams[i]);
3539 AssertRCReturn(rc, rc);
3540 }
3541
3542 return VINF_SUCCESS;
3543}
3544
3545/**
3546 * @callback_method_impl{FNSSMDEVLOADDONE,
3547 * Finishes stream setup and resuming.}
3548 */
3549static DECLCALLBACK(int) hdaR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
3550{
3551 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3552 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
3553 LogFlowFuncEnter();
3554
3555 /*
3556 * Enable all previously active streams.
3557 */
3558 for (size_t i = 0; i < HDA_MAX_STREAMS; i++)
3559 {
3560 PHDASTREAM pStreamShared = &pThis->aStreams[i];
3561
3562 bool fActive = RT_BOOL(HDA_STREAM_REG(pThis, CTL, i) & HDA_SDCTL_RUN);
3563 if (fActive)
3564 {
3565 PHDASTREAMR3 pStreamR3 = &pThisCC->aStreams[i];
3566
3567 /* (Re-)enable the stream. */
3568 int rc2 = hdaR3StreamEnable(pThis, pStreamShared, pStreamR3, true /* fEnable */);
3569 AssertRC(rc2);
3570
3571 /* Add the stream to the device setup. */
3572 rc2 = hdaR3AddStream(pThisCC, &pStreamShared->State.Cfg);
3573 AssertRC(rc2);
3574
3575 /* Use the LPIB to find the current scheduling position. If this isn't
3576 exactly on a scheduling item adjust LPIB down to the start of the
3577 current. This isn't entirely ideal, but it avoid the IRQ counting
3578 issue if we round it upwards. (it is also a lot simpler) */
3579 uint32_t uLpib = HDA_STREAM_REG(pThis, LPIB, i);
3580 AssertLogRelMsgStmt(uLpib < pStreamShared->u32CBL, ("LPIB=%#RX32 CBL=%#RX32\n", uLpib, pStreamShared->u32CBL),
3581 HDA_STREAM_REG(pThis, LPIB, i) = uLpib = 0);
3582
3583 uint32_t off = 0;
3584 for (uint32_t j = 0; j < pStreamShared->State.cSchedule; j++)
3585 {
3586 AssertReturn(pStreamShared->State.aSchedule[j].cbPeriod >= 1 && pStreamShared->State.aSchedule[j].cLoops >= 1,
3587 pDevIns->pHlpR3->pfnSSMSetLoadError(pSSM, VERR_INTERNAL_ERROR_2, RT_SRC_POS,
3588 "Stream #%u, sched #%u: cbPeriod=%u cLoops=%u\n",
3589 pStreamShared->u8SD, j,
3590 pStreamShared->State.aSchedule[j].cbPeriod,
3591 pStreamShared->State.aSchedule[j].cLoops));
3592 uint32_t cbCur = pStreamShared->State.aSchedule[j].cbPeriod
3593 * pStreamShared->State.aSchedule[j].cLoops;
3594 if (uLpib >= off + cbCur)
3595 off += cbCur;
3596 else
3597 {
3598 uint32_t const offDelta = uLpib - off;
3599 uint32_t idxLoop = offDelta / pStreamShared->State.aSchedule[j].cbPeriod;
3600 uint32_t offLoop = offDelta % pStreamShared->State.aSchedule[j].cbPeriod;
3601 if (offLoop)
3602 {
3603 /** @todo somehow bake this into the DMA timer logic. */
3604 LogFunc(("stream #%u: LPIB=%#RX32; adjusting due to scheduling clash: -%#x (j=%u idxLoop=%u cbPeriod=%#x)\n",
3605 pStreamShared->u8SD, uLpib, offLoop, j, idxLoop, pStreamShared->State.aSchedule[j].cbPeriod));
3606 uLpib -= offLoop;
3607 HDA_STREAM_REG(pThis, LPIB, i) = uLpib;
3608 }
3609 pStreamShared->State.idxSchedule = (uint16_t)j;
3610 pStreamShared->State.idxScheduleLoop = (uint16_t)idxLoop;
3611 off = UINT32_MAX;
3612 break;
3613 }
3614 }
3615 Assert(off == UINT32_MAX);
3616
3617 /* Now figure out the current BDLE and the offset within it. */
3618 off = 0;
3619 for (uint32_t j = 0; j < pStreamShared->State.cBdles; j++)
3620 if (uLpib >= off + pStreamShared->State.aBdl[j].cb)
3621 off += pStreamShared->State.aBdl[j].cb;
3622 else
3623 {
3624 pStreamShared->State.idxCurBdle = j;
3625 pStreamShared->State.offCurBdle = uLpib - off;
3626 off = UINT32_MAX;
3627 break;
3628 }
3629 AssertReturn(off == UINT32_MAX, pDevIns->pHlpR3->pfnSSMSetLoadError(pSSM, VERR_INTERNAL_ERROR_3, RT_SRC_POS,
3630 "Stream #%u: LPIB=%#RX32 not found in loaded BDL\n",
3631 pStreamShared->u8SD, uLpib));
3632
3633 /* Avoid going through the timer here by calling the stream's timer function directly.
3634 * Should speed up starting the stream transfers. */
3635 PDMDevHlpTimerLockClock2(pDevIns, pStreamShared->hTimer, &pThis->CritSect, VERR_IGNORED);
3636 uint64_t tsNow = hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
3637 PDMDevHlpTimerUnlockClock2(pDevIns, pStreamShared->hTimer, &pThis->CritSect);
3638
3639 hdaR3StreamMarkStarted(pDevIns, pThis, pStreamShared, tsNow);
3640 }
3641 }
3642
3643 LogFlowFuncLeave();
3644 return VINF_SUCCESS;
3645}
3646
3647/**
3648 * Handles loading of all saved state versions older than the current one.
3649 *
3650 * @param pDevIns The device instance.
3651 * @param pThis Pointer to the shared HDA state.
3652 * @param pThisCC Pointer to the ring-3 HDA state.
3653 * @param pSSM The saved state handle.
3654 * @param uVersion Saved state version to load.
3655 */
3656static int hdaR3LoadExecLegacy(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PSSMHANDLE pSSM, uint32_t uVersion)
3657{
3658 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3659 int rc;
3660
3661 /*
3662 * Load MMIO registers.
3663 */
3664 uint32_t cRegs;
3665 switch (uVersion)
3666 {
3667 case HDA_SAVED_STATE_VERSION_1:
3668 /* Starting with r71199, we would save 112 instead of 113
3669 registers due to some code cleanups. This only affected trunk
3670 builds in the 4.1 development period. */
3671 cRegs = 113;
3672 if (pHlp->pfnSSMHandleRevision(pSSM) >= 71199)
3673 {
3674 uint32_t uVer = pHlp->pfnSSMHandleVersion(pSSM);
3675 if ( VBOX_FULL_VERSION_GET_MAJOR(uVer) == 4
3676 && VBOX_FULL_VERSION_GET_MINOR(uVer) == 0
3677 && VBOX_FULL_VERSION_GET_BUILD(uVer) >= 51)
3678 cRegs = 112;
3679 }
3680 break;
3681
3682 case HDA_SAVED_STATE_VERSION_2:
3683 case HDA_SAVED_STATE_VERSION_3:
3684 cRegs = 112;
3685 AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= 112);
3686 break;
3687
3688 /* Since version 4 we store the register count to stay flexible. */
3689 case HDA_SAVED_STATE_VERSION_4:
3690 case HDA_SAVED_STATE_VERSION_5:
3691 case HDA_SAVED_STATE_VERSION_6:
3692 rc = pHlp->pfnSSMGetU32(pSSM, &cRegs);
3693 AssertRCReturn(rc, rc);
3694 if (cRegs != RT_ELEMENTS(pThis->au32Regs))
3695 LogRel(("HDA: SSM version cRegs is %RU32, expected %RU32\n", cRegs, RT_ELEMENTS(pThis->au32Regs)));
3696 break;
3697
3698 default:
3699 AssertLogRelMsgFailedReturn(("HDA: Internal Error! Didn't expect saved state version %RU32 ending up in hdaR3LoadExecLegacy!\n",
3700 uVersion), VERR_INTERNAL_ERROR_5);
3701 }
3702
3703 if (cRegs >= RT_ELEMENTS(pThis->au32Regs))
3704 {
3705 pHlp->pfnSSMGetMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
3706 pHlp->pfnSSMSkip(pSSM, sizeof(uint32_t) * (cRegs - RT_ELEMENTS(pThis->au32Regs)));
3707 }
3708 else
3709 pHlp->pfnSSMGetMem(pSSM, pThis->au32Regs, sizeof(uint32_t) * cRegs);
3710
3711 /* Make sure to update the base addresses first before initializing any streams down below. */
3712 pThis->u64CORBBase = RT_MAKE_U64(HDA_REG(pThis, CORBLBASE), HDA_REG(pThis, CORBUBASE));
3713 pThis->u64RIRBBase = RT_MAKE_U64(HDA_REG(pThis, RIRBLBASE), HDA_REG(pThis, RIRBUBASE));
3714 pThis->u64DPBase = RT_MAKE_U64(HDA_REG(pThis, DPLBASE) & DPBASE_ADDR_MASK, HDA_REG(pThis, DPUBASE));
3715
3716 /* Also make sure to update the DMA position bit if this was enabled when saving the state. */
3717 pThis->fDMAPosition = RT_BOOL(HDA_REG(pThis, DPLBASE) & RT_BIT_32(0));
3718
3719 /*
3720 * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
3721 *
3722 * Note: Saved states < v5 store LVI (u32BdleMaxCvi) for
3723 * *every* BDLE state, whereas it only needs to be stored
3724 * *once* for every stream. Most of the BDLE state we can
3725 * get out of the registers anyway, so just ignore those values.
3726 *
3727 * Also, only the current BDLE was saved, regardless whether
3728 * there were more than one (and there are at least two entries,
3729 * according to the spec).
3730 */
3731 switch (uVersion)
3732 {
3733 case HDA_SAVED_STATE_VERSION_1:
3734 case HDA_SAVED_STATE_VERSION_2:
3735 case HDA_SAVED_STATE_VERSION_3:
3736 case HDA_SAVED_STATE_VERSION_4:
3737 {
3738 /* Only load the internal states.
3739 * The rest will be initialized from the saved registers later. */
3740
3741 /* Note 1: Only the *current* BDLE for a stream was saved! */
3742 /* Note 2: The stream's saving order is/was fixed, so don't touch! */
3743
3744 HDABDLELEGACY BDLE;
3745
3746 /* Output */
3747 PHDASTREAM pStreamShared = &pThis->aStreams[4];
3748 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, &pThisCC->aStreams[4], 4 /* Stream descriptor, hardcoded */);
3749 AssertRCReturn(rc, rc);
3750 RT_ZERO(BDLE);
3751 rc = pHlp->pfnSSMGetStructEx(pSSM, &BDLE, sizeof(BDLE), 0 /* fFlags */, g_aSSMStreamBdleFields1234, pDevIns);
3752 AssertRCReturn(rc, rc);
3753 pStreamShared->State.idxCurBdle = (uint8_t)BDLE.State.u32BDLIndex; /* not necessary */
3754
3755 /* Microphone-In */
3756 pStreamShared = &pThis->aStreams[2];
3757 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, &pThisCC->aStreams[2], 2 /* Stream descriptor, hardcoded */);
3758 AssertRCReturn(rc, rc);
3759 rc = pHlp->pfnSSMGetStructEx(pSSM, &BDLE, sizeof(BDLE), 0 /* fFlags */, g_aSSMStreamBdleFields1234, pDevIns);
3760 AssertRCReturn(rc, rc);
3761 pStreamShared->State.idxCurBdle = (uint8_t)BDLE.State.u32BDLIndex; /* not necessary */
3762
3763 /* Line-In */
3764 pStreamShared = &pThis->aStreams[0];
3765 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, &pThisCC->aStreams[0], 0 /* Stream descriptor, hardcoded */);
3766 AssertRCReturn(rc, rc);
3767 rc = pHlp->pfnSSMGetStructEx(pSSM, &BDLE, sizeof(BDLE), 0 /* fFlags */, g_aSSMStreamBdleFields1234, pDevIns);
3768 AssertRCReturn(rc, rc);
3769 pStreamShared->State.idxCurBdle = (uint8_t)BDLE.State.u32BDLIndex; /* not necessary */
3770 break;
3771 }
3772
3773 /*
3774 * v5 & v6 - Since v5 we support flexible stream and BDLE counts.
3775 */
3776 default:
3777 {
3778 /* Stream count. */
3779 uint32_t cStreams;
3780 rc = pHlp->pfnSSMGetU32(pSSM, &cStreams);
3781 AssertRCReturn(rc, rc);
3782 if (cStreams > HDA_MAX_STREAMS)
3783 return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
3784 N_("State contains %u streams while %u is the maximum supported"),
3785 cStreams, HDA_MAX_STREAMS);
3786
3787 /* Load stream states. */
3788 for (uint32_t i = 0; i < cStreams; i++)
3789 {
3790 uint8_t idStream;
3791 rc = pHlp->pfnSSMGetU8(pSSM, &idStream);
3792 AssertRCReturn(rc, rc);
3793
3794 HDASTREAM StreamDummyShared;
3795 HDASTREAMR3 StreamDummyR3;
3796 PHDASTREAM pStreamShared = idStream < RT_ELEMENTS(pThis->aStreams) ? &pThis->aStreams[idStream] : &StreamDummyShared;
3797 PHDASTREAMR3 pStreamR3 = idStream < RT_ELEMENTS(pThisCC->aStreams) ? &pThisCC->aStreams[idStream] : &StreamDummyR3;
3798 AssertLogRelMsgStmt(idStream < RT_ELEMENTS(pThisCC->aStreams),
3799 ("HDA stream ID=%RU8 not supported, skipping loadingit ...\n", idStream),
3800 RT_ZERO(StreamDummyShared); RT_ZERO(StreamDummyR3));
3801
3802 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, pStreamR3, idStream);
3803 if (RT_FAILURE(rc))
3804 {
3805 LogRel(("HDA: Stream #%RU32: Setting up of stream %RU8 failed, rc=%Rrc\n", i, idStream, rc));
3806 break;
3807 }
3808
3809 /*
3810 * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
3811 */
3812 if (uVersion == HDA_SAVED_STATE_VERSION_5)
3813 {
3814 struct V5HDASTREAMSTATE /* HDASTREAMSTATE + HDABDLE */
3815 {
3816 uint16_t cBLDEs;
3817 uint16_t uCurBDLE;
3818 uint32_t u32BDLEIndex;
3819 uint32_t cbBelowFIFOW;
3820 uint32_t u32BufOff;
3821 } Tmp;
3822 static SSMFIELD const g_aV5State1Fields[] =
3823 {
3824 SSMFIELD_ENTRY(V5HDASTREAMSTATE, cBLDEs),
3825 SSMFIELD_ENTRY(V5HDASTREAMSTATE, uCurBDLE),
3826 SSMFIELD_ENTRY_TERM()
3827 };
3828 rc = pHlp->pfnSSMGetStructEx(pSSM, &Tmp, sizeof(Tmp), 0 /* fFlags */, g_aV5State1Fields, NULL);
3829 AssertRCReturn(rc, rc);
3830 pStreamShared->State.idxCurBdle = (uint8_t)Tmp.uCurBDLE; /* not necessary */
3831
3832 for (uint16_t a = 0; a < Tmp.cBLDEs; a++)
3833 {
3834 static SSMFIELD const g_aV5State2Fields[] =
3835 {
3836 SSMFIELD_ENTRY(V5HDASTREAMSTATE, u32BDLEIndex),
3837 SSMFIELD_ENTRY_OLD(au8FIFO, 256),
3838 SSMFIELD_ENTRY(V5HDASTREAMSTATE, cbBelowFIFOW),
3839 SSMFIELD_ENTRY_TERM()
3840 };
3841 rc = pHlp->pfnSSMGetStructEx(pSSM, &Tmp, sizeof(Tmp), 0 /* fFlags */, g_aV5State2Fields, NULL);
3842 AssertRCReturn(rc, rc);
3843 }
3844 }
3845 else
3846 {
3847 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State, sizeof(HDASTREAMSTATE),
3848 0 /* fFlags */, g_aSSMStreamStateFields6, NULL);
3849 AssertRCReturn(rc, rc);
3850
3851 HDABDLEDESC IgnDesc;
3852 rc = pHlp->pfnSSMGetStructEx(pSSM, &IgnDesc, sizeof(IgnDesc), 0 /* fFlags */, g_aSSMBDLEDescFields6, pDevIns);
3853 AssertRCReturn(rc, rc);
3854
3855 HDABDLESTATELEGACY IgnState;
3856 rc = pHlp->pfnSSMGetStructEx(pSSM, &IgnState, sizeof(IgnState), 0 /* fFlags */, g_aSSMBDLEStateFields6, NULL);
3857 AssertRCReturn(rc, rc);
3858
3859 Log2Func(("[SD%RU8] LPIB=%RU32, CBL=%RU32, LVI=%RU32\n", idStream, HDA_STREAM_REG(pThis, LPIB, idStream),
3860 HDA_STREAM_REG(pThis, CBL, idStream), HDA_STREAM_REG(pThis, LVI, idStream)));
3861#ifdef LOG_ENABLED
3862 hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
3863#endif
3864 }
3865
3866 } /* for cStreams */
3867 break;
3868 } /* default */
3869 }
3870
3871 return rc;
3872}
3873
3874/**
3875 * @callback_method_impl{FNSSMDEVLOADEXEC}
3876 */
3877static DECLCALLBACK(int) hdaR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
3878{
3879 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3880 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
3881 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3882
3883 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
3884
3885 LogRel2(("hdaR3LoadExec: uVersion=%RU32, uPass=0x%x\n", uVersion, uPass));
3886
3887 /*
3888 * Load Codec nodes states.
3889 */
3890 int rc = hdaR3CodecLoadState(pDevIns, &pThisCC->Codec, pSSM, uVersion);
3891 if (RT_FAILURE(rc))
3892 {
3893 LogRel(("HDA: Failed loading codec state (version %RU32, pass 0x%x), rc=%Rrc\n", uVersion, uPass, rc));
3894 return rc;
3895 }
3896
3897 if (uVersion <= HDA_SAVED_STATE_VERSION_6) /* Handle older saved states? */
3898 return hdaR3LoadExecLegacy(pDevIns, pThis, pThisCC, pSSM, uVersion);
3899
3900 /*
3901 * Load MMIO registers.
3902 */
3903 uint32_t cRegs;
3904 rc = pHlp->pfnSSMGetU32(pSSM, &cRegs); AssertRCReturn(rc, rc);
3905 AssertRCReturn(rc, rc);
3906 if (cRegs != RT_ELEMENTS(pThis->au32Regs))
3907 LogRel(("HDA: SSM version cRegs is %RU32, expected %RU32\n", cRegs, RT_ELEMENTS(pThis->au32Regs)));
3908
3909 if (cRegs >= RT_ELEMENTS(pThis->au32Regs))
3910 {
3911 pHlp->pfnSSMGetMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
3912 rc = pHlp->pfnSSMSkip(pSSM, sizeof(uint32_t) * (cRegs - RT_ELEMENTS(pThis->au32Regs)));
3913 AssertRCReturn(rc, rc);
3914 }
3915 else
3916 {
3917 rc = pHlp->pfnSSMGetMem(pSSM, pThis->au32Regs, sizeof(uint32_t) * cRegs);
3918 AssertRCReturn(rc, rc);
3919 }
3920
3921 /* Make sure to update the base addresses first before initializing any streams down below. */
3922 pThis->u64CORBBase = RT_MAKE_U64(HDA_REG(pThis, CORBLBASE), HDA_REG(pThis, CORBUBASE));
3923 pThis->u64RIRBBase = RT_MAKE_U64(HDA_REG(pThis, RIRBLBASE), HDA_REG(pThis, RIRBUBASE));
3924 pThis->u64DPBase = RT_MAKE_U64(HDA_REG(pThis, DPLBASE) & DPBASE_ADDR_MASK, HDA_REG(pThis, DPUBASE));
3925
3926 /* Also make sure to update the DMA position bit if this was enabled when saving the state. */
3927 pThis->fDMAPosition = RT_BOOL(HDA_REG(pThis, DPLBASE) & RT_BIT_32(0));
3928
3929 /*
3930 * Load controller-specific internals.
3931 */
3932 if ( uVersion >= HDA_SAVED_STATE_WITHOUT_PERIOD
3933 /* Don't annoy other team mates (forgot this for state v7): */
3934 || pHlp->pfnSSMHandleRevision(pSSM) >= 116273
3935 || pHlp->pfnSSMHandleVersion(pSSM) >= VBOX_FULL_VERSION_MAKE(5, 2, 0))
3936 {
3937 pHlp->pfnSSMGetU64(pSSM, &pThis->tsWalClkStart); /* Was current wall clock */
3938 rc = pHlp->pfnSSMGetU8(pSSM, &pThis->u8IRQL);
3939 AssertRCReturn(rc, rc);
3940
3941 /* Convert the saved wall clock timestamp to a start timestamp. */
3942 if (uVersion < HDA_SAVED_STATE_WITHOUT_PERIOD && pThis->tsWalClkStart != 0)
3943 {
3944 uint64_t const cTimerTicksPerSec = PDMDevHlpTimerGetFreq(pDevIns, pThis->aStreams[0].hTimer);
3945 AssertLogRel(cTimerTicksPerSec <= UINT32_MAX);
3946 pThis->tsWalClkStart = ASMMultU64ByU32DivByU32(pThis->tsWalClkStart,
3947 cTimerTicksPerSec,
3948 24000000 /* wall clock freq */);
3949 pThis->tsWalClkStart = PDMDevHlpTimerGet(pDevIns, pThis->aStreams[0].hTimer) - pThis->tsWalClkStart;
3950 }
3951 }
3952
3953 /*
3954 * Load streams.
3955 */
3956 uint32_t cStreams;
3957 rc = pHlp->pfnSSMGetU32(pSSM, &cStreams);
3958 AssertRCReturn(rc, rc);
3959 if (cStreams > HDA_MAX_STREAMS)
3960 return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
3961 N_("State contains %u streams while %u is the maximum supported"),
3962 cStreams, HDA_MAX_STREAMS);
3963 Log2Func(("cStreams=%RU32\n", cStreams));
3964
3965 /* Load stream states. */
3966 for (uint32_t i = 0; i < cStreams; i++)
3967 {
3968 uint8_t idStream;
3969 rc = pHlp->pfnSSMGetU8(pSSM, &idStream);
3970 AssertRCReturn(rc, rc);
3971
3972 /* Paranoia. */
3973 AssertLogRelMsgReturn(idStream < HDA_MAX_STREAMS,
3974 ("HDA: Saved state contains bogus stream ID %RU8 for stream #%RU8", idStream, i),
3975 VERR_SSM_INVALID_STATE);
3976
3977 HDASTREAM StreamDummyShared;
3978 HDASTREAMR3 StreamDummyR3;
3979 PHDASTREAM pStreamShared = idStream < RT_ELEMENTS(pThis->aStreams) ? &pThis->aStreams[idStream] : &StreamDummyShared;
3980 PHDASTREAMR3 pStreamR3 = idStream < RT_ELEMENTS(pThisCC->aStreams) ? &pThisCC->aStreams[idStream] : &StreamDummyR3;
3981 AssertLogRelMsgStmt(idStream < RT_ELEMENTS(pThisCC->aStreams),
3982 ("HDA stream ID=%RU8 not supported, skipping loadingit ...\n", idStream),
3983 RT_ZERO(StreamDummyShared); RT_ZERO(StreamDummyR3));
3984
3985 PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED); /* timer code requires this */
3986 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, pStreamR3, idStream);
3987 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3988 if (RT_FAILURE(rc))
3989 {
3990 LogRel(("HDA: Stream #%RU8: Setting up failed, rc=%Rrc\n", idStream, rc));
3991 /* Continue. */
3992 }
3993
3994 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State, sizeof(HDASTREAMSTATE),
3995 0 /* fFlags */, g_aSSMStreamStateFields7, NULL);
3996 AssertRCReturn(rc, rc);
3997
3998 /*
3999 * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
4000 * Obsolete. Derived from LPID now.
4001 */
4002 HDABDLEDESC IgnDesc;
4003 rc = pHlp->pfnSSMGetStructEx(pSSM, &IgnDesc, sizeof(IgnDesc), 0 /* fFlags */, g_aSSMBDLEDescFields7, NULL);
4004 AssertRCReturn(rc, rc);
4005
4006 HDABDLESTATELEGACY IgnState;
4007 rc = pHlp->pfnSSMGetStructEx(pSSM, &IgnState, sizeof(IgnState), 0 /* fFlags */, g_aSSMBDLEStateFields7, NULL);
4008 AssertRCReturn(rc, rc);
4009
4010 Log2Func(("[SD%RU8]\n", pStreamShared->u8SD));
4011
4012 /*
4013 * Load period state if present.
4014 */
4015 if (uVersion < HDA_SAVED_STATE_WITHOUT_PERIOD)
4016 {
4017 static SSMFIELD const s_aSSMStreamPeriodFields7[] = /* For the removed HDASTREAMPERIOD structure. */
4018 {
4019 SSMFIELD_ENTRY_OLD(u64StartWalClk, sizeof(uint64_t)),
4020 SSMFIELD_ENTRY_OLD(u64ElapsedWalClk, sizeof(uint64_t)),
4021 SSMFIELD_ENTRY_OLD(cFramesTransferred, sizeof(uint32_t)),
4022 SSMFIELD_ENTRY_OLD(cIntPending, sizeof(uint8_t)), /** @todo Not sure what we should for non-zero values on restore... ignoring it for now. */
4023 SSMFIELD_ENTRY_TERM()
4024 };
4025 uint8_t bWhatever = 0;
4026 rc = pHlp->pfnSSMGetStructEx(pSSM, &bWhatever, sizeof(bWhatever), 0 /* fFlags */, s_aSSMStreamPeriodFields7, NULL);
4027 AssertRCReturn(rc, rc);
4028 }
4029
4030 /*
4031 * Load internal DMA buffer.
4032 */
4033 uint32_t cbCircBuf = 0;
4034 pHlp->pfnSSMGetU32(pSSM, &cbCircBuf); /* cbCircBuf */
4035 uint32_t cbCircBufUsed = 0;
4036 rc = pHlp->pfnSSMGetU32(pSSM, &cbCircBufUsed); /* cbCircBuf */
4037 AssertRCReturn(rc, rc);
4038
4039 if (cbCircBuf) /* If 0, skip the buffer. */
4040 {
4041 /* Paranoia. */
4042 AssertLogRelMsgReturn(cbCircBuf <= _32M,
4043 ("HDA: Saved state contains bogus DMA buffer size (%RU32) for stream #%RU8",
4044 cbCircBuf, idStream),
4045 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
4046 AssertLogRelMsgReturn(cbCircBufUsed <= cbCircBuf,
4047 ("HDA: Saved state contains invalid DMA buffer usage (%RU32/%RU32) for stream #%RU8",
4048 cbCircBufUsed, cbCircBuf, idStream),
4049 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
4050
4051 /* Do we need to cre-create the circular buffer do fit the data size? */
4052 if ( pStreamR3->State.pCircBuf
4053 && cbCircBuf != (uint32_t)RTCircBufSize(pStreamR3->State.pCircBuf))
4054 {
4055 RTCircBufDestroy(pStreamR3->State.pCircBuf);
4056 pStreamR3->State.pCircBuf = NULL;
4057 }
4058
4059 rc = RTCircBufCreate(&pStreamR3->State.pCircBuf, cbCircBuf);
4060 AssertRCReturn(rc, rc);
4061 pStreamR3->State.StatDmaBufSize = cbCircBuf;
4062
4063 if (cbCircBufUsed)
4064 {
4065 void *pvBuf = NULL;
4066 size_t cbBuf = 0;
4067 RTCircBufAcquireWriteBlock(pStreamR3->State.pCircBuf, cbCircBufUsed, &pvBuf, &cbBuf);
4068
4069 AssertLogRelMsgReturn(cbBuf == cbCircBufUsed, ("cbBuf=%zu cbCircBufUsed=%zu\n", cbBuf, cbCircBufUsed),
4070 VERR_INTERNAL_ERROR_3);
4071 rc = pHlp->pfnSSMGetMem(pSSM, pvBuf, cbBuf);
4072 AssertRCReturn(rc, rc);
4073 pStreamShared->State.offWrite = cbCircBufUsed;
4074
4075 RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbBuf);
4076
4077 Assert(cbBuf == cbCircBufUsed);
4078 }
4079 }
4080
4081 Log2Func(("[SD%RU8] LPIB=%RU32, CBL=%RU32, LVI=%RU32\n", idStream, HDA_STREAM_REG(pThis, LPIB, idStream),
4082 HDA_STREAM_REG(pThis, CBL, idStream), HDA_STREAM_REG(pThis, LVI, idStream)));
4083#ifdef LOG_ENABLED
4084 hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
4085#endif
4086 /** @todo (Re-)initialize active periods? */
4087
4088 } /* for cStreams */
4089
4090 LogFlowFuncLeaveRC(rc);
4091 return rc;
4092}
4093
4094
4095/*********************************************************************************************************************************
4096* IPRT format type handlers *
4097*********************************************************************************************************************************/
4098
4099/**
4100 * @callback_method_impl{FNRTSTRFORMATTYPE}
4101 */
4102static DECLCALLBACK(size_t) hdaR3StrFmtSDCTL(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
4103 const char *pszType, void const *pvValue,
4104 int cchWidth, int cchPrecision, unsigned fFlags,
4105 void *pvUser)
4106{
4107 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
4108 uint32_t uSDCTL = (uint32_t)(uintptr_t)pvValue;
4109 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
4110 "SDCTL(raw:%#x, DIR:%s, TP:%RTbool, STRIPE:%x, DEIE:%RTbool, FEIE:%RTbool, IOCE:%RTbool, RUN:%RTbool, RESET:%RTbool)",
4111 uSDCTL,
4112 uSDCTL & HDA_SDCTL_DIR ? "OUT" : "IN",
4113 RT_BOOL(uSDCTL & HDA_SDCTL_TP),
4114 (uSDCTL & HDA_SDCTL_STRIPE_MASK) >> HDA_SDCTL_STRIPE_SHIFT,
4115 RT_BOOL(uSDCTL & HDA_SDCTL_DEIE),
4116 RT_BOOL(uSDCTL & HDA_SDCTL_FEIE),
4117 RT_BOOL(uSDCTL & HDA_SDCTL_IOCE),
4118 RT_BOOL(uSDCTL & HDA_SDCTL_RUN),
4119 RT_BOOL(uSDCTL & HDA_SDCTL_SRST));
4120}
4121
4122/**
4123 * @callback_method_impl{FNRTSTRFORMATTYPE}
4124 */
4125static DECLCALLBACK(size_t) hdaR3StrFmtSDFIFOS(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
4126 const char *pszType, void const *pvValue,
4127 int cchWidth, int cchPrecision, unsigned fFlags,
4128 void *pvUser)
4129{
4130 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
4131 uint32_t uSDFIFOS = (uint32_t)(uintptr_t)pvValue;
4132 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOS(raw:%#x, sdfifos:%RU8 B)", uSDFIFOS, uSDFIFOS ? uSDFIFOS + 1 : 0);
4133}
4134
4135/**
4136 * @callback_method_impl{FNRTSTRFORMATTYPE}
4137 */
4138static DECLCALLBACK(size_t) hdaR3StrFmtSDFIFOW(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
4139 const char *pszType, void const *pvValue,
4140 int cchWidth, int cchPrecision, unsigned fFlags,
4141 void *pvUser)
4142{
4143 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
4144 uint32_t uSDFIFOW = (uint32_t)(uintptr_t)pvValue;
4145 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOW(raw: %#0x, sdfifow:%d B)", uSDFIFOW, hdaSDFIFOWToBytes(uSDFIFOW));
4146}
4147
4148/**
4149 * @callback_method_impl{FNRTSTRFORMATTYPE}
4150 */
4151static DECLCALLBACK(size_t) hdaR3StrFmtSDSTS(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
4152 const char *pszType, void const *pvValue,
4153 int cchWidth, int cchPrecision, unsigned fFlags,
4154 void *pvUser)
4155{
4156 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
4157 uint32_t uSdSts = (uint32_t)(uintptr_t)pvValue;
4158 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
4159 "SDSTS(raw:%#0x, fifordy:%RTbool, dese:%RTbool, fifoe:%RTbool, bcis:%RTbool)",
4160 uSdSts,
4161 RT_BOOL(uSdSts & HDA_SDSTS_FIFORDY),
4162 RT_BOOL(uSdSts & HDA_SDSTS_DESE),
4163 RT_BOOL(uSdSts & HDA_SDSTS_FIFOE),
4164 RT_BOOL(uSdSts & HDA_SDSTS_BCIS));
4165}
4166
4167
4168/*********************************************************************************************************************************
4169* Debug Info Item Handlers *
4170*********************************************************************************************************************************/
4171
4172/** Worker for hdaR3DbgInfo. */
4173static int hdaR3DbgLookupRegByName(const char *pszArgs)
4174{
4175 if (pszArgs && *pszArgs != '\0')
4176 for (int iReg = 0; iReg < HDA_NUM_REGS; ++iReg)
4177 if (!RTStrICmp(g_aHdaRegMap[iReg].pszName, pszArgs))
4178 return iReg;
4179 return -1;
4180}
4181
4182/** Worker for hdaR3DbgInfo. */
4183static void hdaR3DbgPrintRegister(PPDMDEVINS pDevIns, PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaIndex)
4184{
4185 /** @todo HDA_REG_IDX_NOMEM & GCAP both uses idxReg zero, no flag or anything
4186 * to tell them appart. */
4187 if (g_aHdaRegMap[iHdaIndex].idxReg != 0 || g_aHdaRegMap[iHdaIndex].pfnRead != hdaRegReadWALCLK)
4188 pHlp->pfnPrintf(pHlp, "%s: 0x%x\n", g_aHdaRegMap[iHdaIndex].pszName, pThis->au32Regs[g_aHdaRegMap[iHdaIndex].idxReg]);
4189 else
4190 {
4191 uint64_t uWallNow = 0;
4192 hdaQueryWallClock(pDevIns, pThis, false /*fDoDma*/, &uWallNow);
4193 pHlp->pfnPrintf(pHlp, "%s: 0x%RX64\n", g_aHdaRegMap[iHdaIndex].pszName, uWallNow);
4194 }
4195}
4196
4197/**
4198 * @callback_method_impl{FNDBGFHANDLERDEV}
4199 */
4200static DECLCALLBACK(void) hdaR3DbgInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4201{
4202 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4203 int idxReg = hdaR3DbgLookupRegByName(pszArgs);
4204 if (idxReg != -1)
4205 hdaR3DbgPrintRegister(pDevIns, pThis, pHlp, idxReg);
4206 else
4207 for (idxReg = 0; idxReg < HDA_NUM_REGS; ++idxReg)
4208 hdaR3DbgPrintRegister(pDevIns, pThis, pHlp, idxReg);
4209}
4210
4211/** Worker for hdaR3DbgInfoStream. */
4212static void hdaR3DbgPrintStream(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int idxStream)
4213{
4214 char szTmp[PDMAUDIOSTRMCFGTOSTRING_MAX];
4215 PHDASTREAM const pStream = &pThis->aStreams[idxStream];
4216 pHlp->pfnPrintf(pHlp, "Stream #%d: %s\n", idxStream, PDMAudioStrmCfgToString(&pStream->State.Cfg, szTmp, sizeof(szTmp)));
4217 pHlp->pfnPrintf(pHlp, " SD%dCTL : %R[sdctl]\n", idxStream, HDA_STREAM_REG(pThis, CTL, idxStream));
4218 pHlp->pfnPrintf(pHlp, " SD%dCTS : %R[sdsts]\n", idxStream, HDA_STREAM_REG(pThis, STS, idxStream));
4219 pHlp->pfnPrintf(pHlp, " SD%dFIFOS: %R[sdfifos]\n", idxStream, HDA_STREAM_REG(pThis, FIFOS, idxStream));
4220 pHlp->pfnPrintf(pHlp, " SD%dFIFOW: %R[sdfifow]\n", idxStream, HDA_STREAM_REG(pThis, FIFOW, idxStream));
4221 pHlp->pfnPrintf(pHlp, " Current BDLE%02u: %s%#RX64 LB %#x%s - off=%#x\n", pStream->State.idxCurBdle, "%%" /*vboxdbg phys prefix*/,
4222 pStream->State.aBdl[pStream->State.idxCurBdle].GCPhys, pStream->State.aBdl[pStream->State.idxCurBdle].cb,
4223 pStream->State.aBdl[pStream->State.idxCurBdle].fFlags ? " IOC" : "", pStream->State.offCurBdle);
4224}
4225
4226/** Worker for hdaR3DbgInfoBDL. */
4227static void hdaR3DbgPrintBDL(PPDMDEVINS pDevIns, PHDASTATE pThis, PCDBGFINFOHLP pHlp, int idxStream)
4228{
4229 const PHDASTREAM pStream = &pThis->aStreams[idxStream];
4230 PCPDMAUDIOPCMPROPS pProps = &pStream->State.Cfg.Props;
4231 uint64_t const u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, idxStream),
4232 HDA_STREAM_REG(pThis, BDPU, idxStream));
4233 uint16_t const u16LVI = HDA_STREAM_REG(pThis, LVI, idxStream);
4234 uint32_t const u32CBL = HDA_STREAM_REG(pThis, CBL, idxStream);
4235 uint8_t const idxCurBdle = pStream->State.idxCurBdle;
4236 pHlp->pfnPrintf(pHlp, "Stream #%d BDL: %s%#011RX64 LB %#x (LVI=%u)\n", idxStream, "%%" /*vboxdbg phys prefix*/,
4237 u64BaseDMA, u16LVI * sizeof(HDABDLEDESC), u16LVI);
4238 if (u64BaseDMA || idxCurBdle != 0 || pStream->State.aBdl[idxCurBdle].GCPhys != 0 || pStream->State.aBdl[idxCurBdle].cb != 0)
4239 pHlp->pfnPrintf(pHlp, " Current: BDLE%03u: %s%#011RX64 LB %#x%s - off=%#x LPIB=%#RX32\n",
4240 pStream->State.idxCurBdle, "%%" /*vboxdbg phys prefix*/,
4241 pStream->State.aBdl[idxCurBdle].GCPhys, pStream->State.aBdl[idxCurBdle].cb,
4242 pStream->State.aBdl[idxCurBdle].fFlags ? " IOC" : "", pStream->State.offCurBdle,
4243 HDA_STREAM_REG(pThis, LPIB, idxStream));
4244 if (!u64BaseDMA)
4245 return;
4246
4247 /*
4248 * The BDL:
4249 */
4250 uint64_t cbTotal = 0;
4251 for (uint16_t i = 0; i < u16LVI + 1; i++)
4252 {
4253 HDABDLEDESC bd = {0, 0, 0};
4254 PDMDevHlpPCIPhysRead(pDevIns, u64BaseDMA + i * sizeof(HDABDLEDESC), &bd, sizeof(bd));
4255
4256 char szFlags[64];
4257 szFlags[0] = '\0';
4258 if (bd.fFlags & ~HDA_BDLE_F_IOC)
4259 RTStrPrintf(szFlags, sizeof(szFlags), " !!fFlags=%#x!!\n", bd.fFlags);
4260 pHlp->pfnPrintf(pHlp, " %sBDLE%03u: %s%#011RX64 LB %#06x (%RU64 us) %s%s\n", idxCurBdle == i ? "=>" : " ", i, "%%",
4261 bd.u64BufAddr, bd.u32BufSize, PDMAudioPropsBytesToMicro(pProps, bd.u32BufSize),
4262 bd.fFlags & HDA_BDLE_F_IOC ? " IOC=1" : "", szFlags);
4263
4264 if (memcmp(&bd, &pStream->State.aBdl[i], sizeof(bd)) != 0)
4265 {
4266 szFlags[0] = '\0';
4267 if (bd.fFlags & ~HDA_BDLE_F_IOC)
4268 RTStrPrintf(szFlags, sizeof(szFlags), " !!fFlags=%#x!!\n", bd.fFlags);
4269 pHlp->pfnPrintf(pHlp, " !!!loaded: %s%#011RX64 LB %#06x %s%s\n", "%%", pStream->State.aBdl[i].GCPhys,
4270 pStream->State.aBdl[i].cb, pStream->State.aBdl[i].fFlags & HDA_BDLE_F_IOC ? " IOC=1" : "", szFlags);
4271 }
4272
4273 cbTotal += bd.u32BufSize;
4274 }
4275 pHlp->pfnPrintf(pHlp, " Total: %#RX64 bytes (%RU64), %RU64 ms\n", cbTotal, cbTotal,
4276 PDMAudioPropsBytesToMilli(pProps, (uint32_t)cbTotal));
4277 if (cbTotal != u32CBL)
4278 pHlp->pfnPrintf(pHlp, " Warning: %#RX64 bytes does not match CBL (%#RX64)!\n", cbTotal, u32CBL);
4279
4280 /*
4281 * The scheduling plan.
4282 */
4283 uint16_t const idxSchedule = pStream->State.idxSchedule;
4284 pHlp->pfnPrintf(pHlp, " Scheduling: %u items, %u prologue. Current: %u, loop %u.\n", pStream->State.cSchedule,
4285 pStream->State.cSchedulePrologue, idxSchedule, pStream->State.idxScheduleLoop);
4286 for (uint16_t i = 0; i < pStream->State.cSchedule; i++)
4287 pHlp->pfnPrintf(pHlp, " %s#%02u: %#x bytes, %u loop%s, %RU32 ticks. BDLE%u thru BDLE%u\n",
4288 i == idxSchedule ? "=>" : " ", i,
4289 pStream->State.aSchedule[i].cbPeriod, pStream->State.aSchedule[i].cLoops,
4290 pStream->State.aSchedule[i].cLoops == 1 ? "" : "s",
4291 pStream->State.aSchedule[i].cPeriodTicks, pStream->State.aSchedule[i].idxFirst,
4292 pStream->State.aSchedule[i].idxFirst + pStream->State.aSchedule[i].cEntries - 1);
4293}
4294
4295/** Used by hdaR3DbgInfoStream and hdaR3DbgInfoBDL. */
4296static int hdaR3DbgLookupStrmIdx(PCDBGFINFOHLP pHlp, const char *pszArgs)
4297{
4298 if (pszArgs && *pszArgs)
4299 {
4300 int32_t idxStream;
4301 int rc = RTStrToInt32Full(pszArgs, 0, &idxStream);
4302 if (RT_SUCCESS(rc) && idxStream >= -1 && idxStream < HDA_MAX_STREAMS)
4303 return idxStream;
4304 pHlp->pfnPrintf(pHlp, "Argument '%s' is not a valid stream number!\n", pszArgs);
4305 }
4306 return -1;
4307}
4308
4309/**
4310 * @callback_method_impl{FNDBGFHANDLERDEV, hdastream}
4311 */
4312static DECLCALLBACK(void) hdaR3DbgInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4313{
4314 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4315 int idxStream = hdaR3DbgLookupStrmIdx(pHlp, pszArgs);
4316 if (idxStream != -1)
4317 hdaR3DbgPrintStream(pThis, pHlp, idxStream);
4318 else
4319 for (idxStream = 0; idxStream < HDA_MAX_STREAMS; ++idxStream)
4320 hdaR3DbgPrintStream(pThis, pHlp, idxStream);
4321}
4322
4323/**
4324 * @callback_method_impl{FNDBGFHANDLERDEV, hdabdl}
4325 */
4326static DECLCALLBACK(void) hdaR3DbgInfoBDL(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4327{
4328 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4329 int idxStream = hdaR3DbgLookupStrmIdx(pHlp, pszArgs);
4330 if (idxStream != -1)
4331 hdaR3DbgPrintBDL(pDevIns, pThis, pHlp, idxStream);
4332 else
4333 {
4334 for (idxStream = 0; idxStream < HDA_MAX_STREAMS; ++idxStream)
4335 hdaR3DbgPrintBDL(pDevIns, pThis, pHlp, idxStream);
4336 idxStream = -1;
4337 }
4338
4339 /*
4340 * DMA stream positions:
4341 */
4342 uint64_t const uDPBase = pThis->u64DPBase & DPBASE_ADDR_MASK;
4343 pHlp->pfnPrintf(pHlp, "DMA counters %#011RX64 LB %#x, %s:\n", uDPBase, HDA_MAX_STREAMS * 2 * sizeof(uint32_t),
4344 pThis->fDMAPosition ? "enabled" : "disabled");
4345 if (uDPBase)
4346 {
4347 struct
4348 {
4349 uint32_t off, uReserved;
4350 } aPositions[HDA_MAX_STREAMS];
4351 RT_ZERO(aPositions);
4352 PDMDevHlpPCIPhysRead(pDevIns, uDPBase , &aPositions[0], sizeof(aPositions));
4353
4354 for (unsigned i = 0; i < RT_ELEMENTS(aPositions); i++)
4355 if (idxStream == -1 || i == (unsigned)idxStream) /* lazy bird */
4356 {
4357 char szReserved[64];
4358 szReserved[0] = '\0';
4359 if (aPositions[i].uReserved != 0)
4360 RTStrPrintf(szReserved, sizeof(szReserved), " reserved=%#x", aPositions[i].uReserved);
4361 pHlp->pfnPrintf(pHlp, " Stream #%u DMA @ %#x%s\n", i, aPositions[i].off, szReserved);
4362 }
4363 }
4364}
4365
4366/**
4367 * @callback_method_impl{FNDBGFHANDLERDEV, hdcnodes}
4368 */
4369static DECLCALLBACK(void) hdaR3DbgInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4370{
4371 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4372
4373 if (pThisCC->Codec.pfnDbgListNodes)
4374 pThisCC->Codec.pfnDbgListNodes(&pThisCC->Codec, pHlp, pszArgs);
4375 else
4376 pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
4377}
4378
4379/**
4380 * @callback_method_impl{FNDBGFHANDLERDEV, hdcselector}
4381 */
4382static DECLCALLBACK(void) hdaR3DbgInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4383{
4384 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4385
4386 if (pThisCC->Codec.pfnDbgSelector)
4387 pThisCC->Codec.pfnDbgSelector(&pThisCC->Codec, pHlp, pszArgs);
4388 else
4389 pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
4390}
4391
4392/**
4393 * @callback_method_impl{FNDBGFHANDLERDEV, hdamixer}
4394 */
4395static DECLCALLBACK(void) hdaR3DbgInfoMixer(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4396{
4397 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4398 if (pThisCC->pMixer)
4399 AudioMixerDebug(pThisCC->pMixer, pHlp, pszArgs);
4400 else
4401 pHlp->pfnPrintf(pHlp, "Mixer not available\n");
4402}
4403
4404
4405/*********************************************************************************************************************************
4406* PDMIBASE *
4407*********************************************************************************************************************************/
4408
4409/**
4410 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4411 */
4412static DECLCALLBACK(void *) hdaR3QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
4413{
4414 PHDASTATER3 pThisCC = RT_FROM_MEMBER(pInterface, HDASTATER3, IBase);
4415
4416 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
4417 return NULL;
4418}
4419
4420
4421/*********************************************************************************************************************************
4422* PDMDEVREGR3 *
4423*********************************************************************************************************************************/
4424
4425/**
4426 * Worker for hdaR3Construct() and hdaR3Attach().
4427 *
4428 * @returns VBox status code.
4429 * @param pDevIns The device instance.
4430 * @param pThis The shared HDA device state.
4431 * @param pThisCC The ring-3 HDA device state.
4432 * @param uLUN The logical unit which is being detached.
4433 * @param ppDrv Attached driver instance on success. Optional.
4434 */
4435static int hdaR3AttachInternal(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, unsigned uLUN, PHDADRIVER *ppDrv)
4436{
4437 /*
4438 * Attach driver.
4439 */
4440 char *pszDesc = RTStrAPrintf2("Audio driver port (HDA) for LUN#%u", uLUN);
4441 AssertLogRelReturn(pszDesc, VERR_NO_STR_MEMORY);
4442
4443 PPDMIBASE pDrvBase;
4444 int rc = PDMDevHlpDriverAttach(pDevIns, uLUN, &pThisCC->IBase, &pDrvBase, pszDesc);
4445 if (RT_SUCCESS(rc))
4446 {
4447 PHDADRIVER pDrv = (PHDADRIVER)RTMemAllocZ(sizeof(HDADRIVER));
4448 if (pDrv)
4449 {
4450 pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
4451 AssertPtr(pDrv->pConnector);
4452 if (RT_VALID_PTR(pDrv->pConnector))
4453 {
4454 pDrv->pDrvBase = pDrvBase;
4455 pDrv->pHDAStateShared = pThis;
4456 pDrv->pHDAStateR3 = pThisCC;
4457 pDrv->uLUN = uLUN;
4458
4459 /* Attach to driver list if not attached yet. */
4460 if (!pDrv->fAttached)
4461 {
4462 RTListAppend(&pThisCC->lstDrv, &pDrv->Node);
4463 pDrv->fAttached = true;
4464 }
4465
4466 if (ppDrv)
4467 *ppDrv = pDrv;
4468
4469 /*
4470 * While we're here, give the windows backends a hint about our typical playback
4471 * configuration.
4472 * Note! If 48000Hz is advertised to the guest, add it here.
4473 */
4474 if ( pDrv->pConnector
4475 && pDrv->pConnector->pfnStreamConfigHint)
4476 {
4477 PDMAUDIOSTREAMCFG Cfg;
4478 RT_ZERO(Cfg);
4479 Cfg.enmDir = PDMAUDIODIR_OUT;
4480 Cfg.enmPath = PDMAUDIOPATH_OUT_FRONT;
4481 Cfg.Device.cMsSchedulingHint = 10;
4482 Cfg.Backend.cFramesPreBuffering = UINT32_MAX;
4483 PDMAudioPropsInit(&Cfg.Props, 2, true /*fSigned*/, 2, 44100);
4484 RTStrPrintf(Cfg.szName, sizeof(Cfg.szName), "output 44.1kHz 2ch S16 (HDA config hint)");
4485
4486 pDrv->pConnector->pfnStreamConfigHint(pDrv->pConnector, &Cfg); /* (may trash CfgReq) */
4487 }
4488
4489 LogFunc(("LUN#%u: returns VINF_SUCCESS (pCon=%p)\n", uLUN, pDrv->pConnector));
4490 return VINF_SUCCESS;
4491 }
4492
4493 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
4494 }
4495 else
4496 rc = VERR_NO_MEMORY;
4497 }
4498 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4499 LogFunc(("No attached driver for LUN #%u\n", uLUN));
4500 else
4501 LogFunc(("Failed attaching driver for LUN #%u: %Rrc\n", uLUN, rc));
4502
4503 RTStrFree(pszDesc);
4504 LogFunc(("LUN#%u: rc=%Rrc\n", uLUN, rc));
4505 return rc;
4506}
4507
4508
4509/**
4510 * @interface_method_impl{PDMDEVREG,pfnAttach}
4511 */
4512static DECLCALLBACK(int) hdaR3Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
4513{
4514 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4515 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4516 RT_NOREF(fFlags);
4517 LogFunc(("uLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
4518
4519 DEVHDA_LOCK_RETURN(pDevIns, pThis, VERR_IGNORED);
4520
4521 PHDADRIVER pDrv;
4522 int rc = hdaR3AttachInternal(pDevIns, pThis, pThisCC, uLUN, &pDrv);
4523 if (RT_SUCCESS(rc))
4524 {
4525 int rc2 = hdaR3MixerAddDrv(pDevIns, pThisCC, pDrv);
4526 if (RT_FAILURE(rc2))
4527 LogFunc(("hdaR3MixerAddDrv failed with %Rrc (ignored)\n", rc2));
4528 }
4529
4530 DEVHDA_UNLOCK(pDevIns, pThis);
4531 return rc;
4532}
4533
4534
4535/**
4536 * Worker for hdaR3Detach that does all but free pDrv.
4537 *
4538 * This is called to let the device detach from a driver for a specified LUN
4539 * at runtime.
4540 *
4541 * @param pDevIns The device instance.
4542 * @param pThisCC The ring-3 HDA device state.
4543 * @param pDrv Driver to detach from device.
4544 */
4545static void hdaR3DetachInternal(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PHDADRIVER pDrv)
4546{
4547 /* Remove the driver from our list and destory it's associated streams.
4548 This also will un-set the driver as a recording source (if associated). */
4549 hdaR3MixerRemoveDrv(pDevIns, pThisCC, pDrv);
4550 LogFunc(("LUN#%u detached\n", pDrv->uLUN));
4551}
4552
4553
4554/**
4555 * @interface_method_impl{PDMDEVREG,pfnDetach}
4556 */
4557static DECLCALLBACK(void) hdaR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4558{
4559 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4560 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4561 RT_NOREF(fFlags);
4562 LogFunc(("iLUN=%u, fFlags=%#x\n", iLUN, fFlags));
4563
4564 DEVHDA_LOCK(pDevIns, pThis);
4565
4566 PHDADRIVER pDrv;
4567 RTListForEach(&pThisCC->lstDrv, pDrv, HDADRIVER, Node)
4568 {
4569 if (pDrv->uLUN == iLUN)
4570 {
4571 hdaR3DetachInternal(pDevIns, pThisCC, pDrv);
4572 RTMemFree(pDrv);
4573 DEVHDA_UNLOCK(pDevIns, pThis);
4574 return;
4575 }
4576 }
4577
4578 DEVHDA_UNLOCK(pDevIns, pThis);
4579 LogFunc(("LUN#%u was not found\n", iLUN));
4580}
4581
4582
4583/**
4584 * Powers off the device.
4585 *
4586 * @param pDevIns Device instance to power off.
4587 */
4588static DECLCALLBACK(void) hdaR3PowerOff(PPDMDEVINS pDevIns)
4589{
4590 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4591 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4592
4593 DEVHDA_LOCK_RETURN_VOID(pDevIns, pThis);
4594
4595 LogRel2(("HDA: Powering off ...\n"));
4596
4597/** @todo r=bird: What this "releasing references" and whatever here is
4598 * referring to, is apparently that the device is destroyed after the
4599 * drivers, so creating trouble as those structures have been torn down
4600 * already... Reverse order, like we do for power off? Need a new
4601 * PDMDEVREG flag. */
4602
4603 /* Ditto goes for the codec, which in turn uses the mixer. */
4604 hdaR3CodecPowerOff(&pThisCC->Codec);
4605
4606 /* This is to prevent us from calling into the mixer and mixer sink code
4607 after it has been destroyed below. */
4608 for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
4609 pThisCC->aStreams[i].State.pAioRegSink = NULL; /* don't need to remove, we're destorying it. */
4610
4611 /*
4612 * Note: Destroy the mixer while powering off and *not* in hdaR3Destruct,
4613 * giving the mixer the chance to release any references held to
4614 * PDM audio streams it maintains.
4615 */
4616 if (pThisCC->pMixer)
4617 {
4618 AudioMixerDestroy(pThisCC->pMixer, pDevIns);
4619 pThisCC->pMixer = NULL;
4620 }
4621
4622 DEVHDA_UNLOCK(pDevIns, pThis);
4623}
4624
4625
4626/**
4627 * @interface_method_impl{PDMDEVREG,pfnReset}
4628 */
4629static DECLCALLBACK(void) hdaR3Reset(PPDMDEVINS pDevIns)
4630{
4631 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4632 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4633
4634 LogFlowFuncEnter();
4635
4636 DEVHDA_LOCK_RETURN_VOID(pDevIns, pThis);
4637
4638 /*
4639 * 18.2.6,7 defines that values of this registers might be cleared on power on/reset
4640 * hdaR3Reset shouldn't affects these registers.
4641 */
4642 HDA_REG(pThis, WAKEEN) = 0x0;
4643
4644 hdaR3GCTLReset(pDevIns, pThis, pThisCC);
4645
4646 /* Indicate that HDA is not in reset. The firmware is supposed to (un)reset HDA,
4647 * but we can take a shortcut.
4648 */
4649 HDA_REG(pThis, GCTL) = HDA_GCTL_CRST;
4650
4651 DEVHDA_UNLOCK(pDevIns, pThis);
4652}
4653
4654
4655/**
4656 * @interface_method_impl{PDMDEVREG,pfnDestruct}
4657 */
4658static DECLCALLBACK(int) hdaR3Destruct(PPDMDEVINS pDevIns)
4659{
4660 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); /* this shall come first */
4661 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4662 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4663
4664 if (PDMCritSectIsInitialized(&pThis->CritSect))
4665 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
4666
4667 PHDADRIVER pDrv;
4668 while (!RTListIsEmpty(&pThisCC->lstDrv))
4669 {
4670 pDrv = RTListGetFirst(&pThisCC->lstDrv, HDADRIVER, Node);
4671
4672 RTListNodeRemove(&pDrv->Node);
4673 RTMemFree(pDrv);
4674 }
4675
4676 hdaCodecDestruct(&pThisCC->Codec);
4677
4678 for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
4679 hdaR3StreamDestroy(&pThisCC->aStreams[i]);
4680
4681 /* We don't always go via PowerOff, so make sure the mixer is destroyed. */
4682 if (pThisCC->pMixer)
4683 {
4684 AudioMixerDestroy(pThisCC->pMixer, pDevIns);
4685 pThisCC->pMixer = NULL;
4686 }
4687
4688 if (PDMCritSectIsInitialized(&pThis->CritSect))
4689 {
4690 PDMCritSectLeave(&pThis->CritSect);
4691 PDMR3CritSectDelete(&pThis->CritSect);
4692 }
4693 return VINF_SUCCESS;
4694}
4695
4696
4697/**
4698 * @interface_method_impl{PDMDEVREG,pfnConstruct}
4699 */
4700static DECLCALLBACK(int) hdaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
4701{
4702 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* this shall come first */
4703 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4704 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4705 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4706 Assert(iInstance == 0); RT_NOREF(iInstance);
4707
4708 /*
4709 * Initialize the state sufficently to make the destructor work.
4710 */
4711 pThis->uAlignmentCheckMagic = HDASTATE_ALIGNMENT_CHECK_MAGIC;
4712 RTListInit(&pThisCC->lstDrv);
4713 pThis->cbCorbBuf = HDA_CORB_SIZE * HDA_CORB_ELEMENT_SIZE;
4714 pThis->cbRirbBuf = HDA_RIRB_SIZE * HDA_RIRB_ELEMENT_SIZE;
4715 pThis->hCorbDmaTask = NIL_PDMTASKHANDLE;
4716
4717 /** @todo r=bird: There are probably other things which should be
4718 * initialized here before we start failing. */
4719
4720 /*
4721 * Validate and read configuration.
4722 */
4723 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
4724 "BufSizeInMs"
4725 "|BufSizeOutMs"
4726 "|DebugEnabled"
4727 "|DebugPathOut",
4728 "");
4729
4730 /** @devcfgm{hda,BufSizeInMs,uint16_t,0,2000,0,ms}
4731 * The size of the DMA buffer for input streams expressed in milliseconds. */
4732 int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeInMs", &pThis->cMsCircBufIn, 0);
4733 if (RT_FAILURE(rc))
4734 return PDMDEV_SET_ERROR(pDevIns, rc,
4735 N_("HDA configuration error: failed to read 'BufSizeInMs' as 16-bit unsigned integer"));
4736 if (pThis->cMsCircBufIn > 2000)
4737 return PDMDEV_SET_ERROR(pDevIns, VERR_OUT_OF_RANGE,
4738 N_("HDA configuration error: 'BufSizeInMs' is out of bound, max 2000 ms"));
4739
4740 /** @devcfgm{hda,BufSizeOutMs,uint16_t,0,2000,0,ms}
4741 * The size of the DMA buffer for output streams expressed in milliseconds. */
4742 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeOutMs", &pThis->cMsCircBufOut, 0);
4743 if (RT_FAILURE(rc))
4744 return PDMDEV_SET_ERROR(pDevIns, rc,
4745 N_("HDA configuration error: failed to read 'BufSizeOutMs' as 16-bit unsigned integer"));
4746 if (pThis->cMsCircBufOut > 2000)
4747 return PDMDEV_SET_ERROR(pDevIns, VERR_OUT_OF_RANGE,
4748 N_("HDA configuration error: 'BufSizeOutMs' is out of bound, max 2000 ms"));
4749
4750 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DebugEnabled", &pThisCC->Dbg.fEnabled, false);
4751 if (RT_FAILURE(rc))
4752 return PDMDEV_SET_ERROR(pDevIns, rc,
4753 N_("HDA configuration error: failed to read debugging enabled flag as boolean"));
4754
4755 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "DebugPathOut", &pThisCC->Dbg.pszOutPath, NULL);
4756 if (RT_FAILURE(rc))
4757 return PDMDEV_SET_ERROR(pDevIns, rc,
4758 N_("HDA configuration error: failed to read debugging output path flag as string"));
4759 if (pThisCC->Dbg.fEnabled)
4760 LogRel2(("HDA: Debug output will be saved to '%s'\n", pThisCC->Dbg.pszOutPath));
4761
4762 /*
4763 * Use our own critical section for the device instead of the default
4764 * one provided by PDM. This allows fine-grained locking in combination
4765 * with TM when timer-specific stuff is being called in e.g. the MMIO handlers.
4766 */
4767 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "HDA");
4768 AssertRCReturn(rc, rc);
4769
4770 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
4771 AssertRCReturn(rc, rc);
4772
4773 /*
4774 * Initialize data (most of it anyway).
4775 */
4776 pThisCC->pDevIns = pDevIns;
4777 /* IBase */
4778 pThisCC->IBase.pfnQueryInterface = hdaR3QueryInterface;
4779
4780 /* PCI Device */
4781 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
4782 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
4783
4784 PDMPciDevSetVendorId( pPciDev, HDA_PCI_VENDOR_ID); /* nVidia */
4785 PDMPciDevSetDeviceId( pPciDev, HDA_PCI_DEVICE_ID); /* HDA */
4786
4787 PDMPciDevSetCommand( pPciDev, 0x0000); /* 04 rw,ro - pcicmd. */
4788 PDMPciDevSetStatus( pPciDev, VBOX_PCI_STATUS_CAP_LIST); /* 06 rwc?,ro? - pcists. */
4789 PDMPciDevSetRevisionId( pPciDev, 0x01); /* 08 ro - rid. */
4790 PDMPciDevSetClassProg( pPciDev, 0x00); /* 09 ro - pi. */
4791 PDMPciDevSetClassSub( pPciDev, 0x03); /* 0a ro - scc; 03 == HDA. */
4792 PDMPciDevSetClassBase( pPciDev, 0x04); /* 0b ro - bcc; 04 == multimedia. */
4793 PDMPciDevSetHeaderType( pPciDev, 0x00); /* 0e ro - headtyp. */
4794 PDMPciDevSetBaseAddress( pPciDev, 0, /* 10 rw - MMIO */
4795 false /* fIoSpace */, false /* fPrefetchable */, true /* f64Bit */, 0x00000000);
4796 PDMPciDevSetInterruptLine( pPciDev, 0x00); /* 3c rw. */
4797 PDMPciDevSetInterruptPin( pPciDev, 0x01); /* 3d ro - INTA#. */
4798
4799# if defined(HDA_AS_PCI_EXPRESS)
4800 PDMPciDevSetCapabilityList(pPciDev, 0x80);
4801# elif defined(VBOX_WITH_MSI_DEVICES)
4802 PDMPciDevSetCapabilityList(pPciDev, 0x60);
4803# else
4804 PDMPciDevSetCapabilityList(pPciDev, 0x50); /* ICH6 datasheet 18.1.16 */
4805# endif
4806
4807 /// @todo r=michaln: If there are really no PDMPciDevSetXx for these, the
4808 /// meaning of these values needs to be properly documented!
4809 /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
4810 PDMPciDevSetByte( pPciDev, 0x40, 0x01);
4811
4812 /* Power Management */
4813 PDMPciDevSetByte( pPciDev, 0x50 + 0, VBOX_PCI_CAP_ID_PM);
4814 PDMPciDevSetByte( pPciDev, 0x50 + 1, 0x0); /* next */
4815 PDMPciDevSetWord( pPciDev, 0x50 + 2, VBOX_PCI_PM_CAP_DSI | 0x02 /* version, PM1.1 */ );
4816
4817# ifdef HDA_AS_PCI_EXPRESS
4818 /* PCI Express */
4819 PDMPciDevSetByte( pPciDev, 0x80 + 0, VBOX_PCI_CAP_ID_EXP); /* PCI_Express */
4820 PDMPciDevSetByte( pPciDev, 0x80 + 1, 0x60); /* next */
4821 /* Device flags */
4822 PDMPciDevSetWord( pPciDev, 0x80 + 2,
4823 1 /* version */
4824 | (VBOX_PCI_EXP_TYPE_ROOT_INT_EP << 4) /* Root Complex Integrated Endpoint */
4825 | (100 << 9) /* MSI */ );
4826 /* Device capabilities */
4827 PDMPciDevSetDWord( pPciDev, 0x80 + 4, VBOX_PCI_EXP_DEVCAP_FLRESET);
4828 /* Device control */
4829 PDMPciDevSetWord( pPciDev, 0x80 + 8, 0);
4830 /* Device status */
4831 PDMPciDevSetWord( pPciDev, 0x80 + 10, 0);
4832 /* Link caps */
4833 PDMPciDevSetDWord( pPciDev, 0x80 + 12, 0);
4834 /* Link control */
4835 PDMPciDevSetWord( pPciDev, 0x80 + 16, 0);
4836 /* Link status */
4837 PDMPciDevSetWord( pPciDev, 0x80 + 18, 0);
4838 /* Slot capabilities */
4839 PDMPciDevSetDWord( pPciDev, 0x80 + 20, 0);
4840 /* Slot control */
4841 PDMPciDevSetWord( pPciDev, 0x80 + 24, 0);
4842 /* Slot status */
4843 PDMPciDevSetWord( pPciDev, 0x80 + 26, 0);
4844 /* Root control */
4845 PDMPciDevSetWord( pPciDev, 0x80 + 28, 0);
4846 /* Root capabilities */
4847 PDMPciDevSetWord( pPciDev, 0x80 + 30, 0);
4848 /* Root status */
4849 PDMPciDevSetDWord( pPciDev, 0x80 + 32, 0);
4850 /* Device capabilities 2 */
4851 PDMPciDevSetDWord( pPciDev, 0x80 + 36, 0);
4852 /* Device control 2 */
4853 PDMPciDevSetQWord( pPciDev, 0x80 + 40, 0);
4854 /* Link control 2 */
4855 PDMPciDevSetQWord( pPciDev, 0x80 + 48, 0);
4856 /* Slot control 2 */
4857 PDMPciDevSetWord( pPciDev, 0x80 + 56, 0);
4858# endif /* HDA_AS_PCI_EXPRESS */
4859
4860 /*
4861 * Register the PCI device.
4862 */
4863 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
4864 AssertRCReturn(rc, rc);
4865
4866 /** @todo r=bird: The IOMMMIO_FLAGS_READ_DWORD flag isn't entirely optimal,
4867 * as several frequently used registers aren't dword sized. 6.0 and earlier
4868 * will go to ring-3 to handle accesses to any such register, where-as 6.1 and
4869 * later will do trivial register reads in ring-0. Real optimal code would use
4870 * IOMMMIO_FLAGS_READ_PASSTHRU and do the necessary extra work to deal with
4871 * anything the guest may throw at us. */
4872 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 0, 0x4000, PCI_ADDRESS_SPACE_MEM, hdaMmioWrite, hdaMmioRead, NULL /*pvUser*/,
4873 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU, "HDA", &pThis->hMmio);
4874 AssertRCReturn(rc, rc);
4875
4876# ifdef VBOX_WITH_MSI_DEVICES
4877 PDMMSIREG MsiReg;
4878 RT_ZERO(MsiReg);
4879 MsiReg.cMsiVectors = 1;
4880 MsiReg.iMsiCapOffset = 0x60;
4881 MsiReg.iMsiNextOffset = 0x50;
4882 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
4883 if (RT_FAILURE(rc))
4884 {
4885 /* That's OK, we can work without MSI */
4886 PDMPciDevSetCapabilityList(pPciDev, 0x50);
4887 }
4888# endif
4889
4890 /* Create task for continuing CORB DMA in ring-3. */
4891 rc = PDMDevHlpTaskCreate(pDevIns, PDMTASK_F_RZ, "HDA CORB DMA",
4892 hdaR3CorbDmaTaskWorker, NULL /*pvUser*/, &pThis->hCorbDmaTask);
4893 AssertRCReturn(rc,rc);
4894
4895 rc = PDMDevHlpSSMRegisterEx(pDevIns, HDA_SAVED_STATE_VERSION, sizeof(*pThis), NULL /*pszBefore*/,
4896 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
4897 NULL /*pfnSavePrep*/, hdaR3SaveExec, NULL /*pfnSaveDone*/,
4898 NULL /*pfnLoadPrep*/, hdaR3LoadExec, hdaR3LoadDone);
4899 AssertRCReturn(rc, rc);
4900
4901 /*
4902 * Attach drivers. We ASSUME they are configured consecutively without any
4903 * gaps, so we stop when we hit the first LUN w/o a driver configured.
4904 */
4905 for (unsigned iLun = 0; ; iLun++)
4906 {
4907 AssertBreak(iLun < UINT8_MAX);
4908 LogFunc(("Trying to attach driver for LUN#%u ...\n", iLun));
4909 rc = hdaR3AttachInternal(pDevIns, pThis, pThisCC, iLun, NULL /* ppDrv */);
4910 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4911 {
4912 LogFunc(("cLUNs=%u\n", iLun));
4913 break;
4914 }
4915 AssertLogRelMsgReturn(RT_SUCCESS(rc), ("LUN#%u: rc=%Rrc\n", iLun, rc), rc);
4916 }
4917
4918 /*
4919 * Create the mixer.
4920 */
4921 uint32_t fMixer = AUDMIXER_FLAGS_NONE;
4922 if (pThisCC->Dbg.fEnabled)
4923 fMixer |= AUDMIXER_FLAGS_DEBUG;
4924 rc = AudioMixerCreate("HDA Mixer", fMixer, &pThisCC->pMixer);
4925 AssertRCReturn(rc, rc);
4926
4927 /*
4928 * Add mixer output sinks.
4929 */
4930# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
4931 rc = AudioMixerCreateSink(pThisCC->pMixer, "Front",
4932 PDMAUDIODIR_OUT, pDevIns, &pThisCC->SinkFront.pMixSink);
4933 AssertRCReturn(rc, rc);
4934 rc = AudioMixerCreateSink(pThisCC->pMixer, "Center+Subwoofer",
4935 PDMAUDIODIR_OUT, pDevIns, &pThisCC->SinkCenterLFE.pMixSink);
4936 AssertRCReturn(rc, rc);
4937 rc = AudioMixerCreateSink(pThisCC->pMixer, "Rear",
4938 PDMAUDIODIR_OUT, pDevIns, &pThisCC->SinkRear.pMixSink);
4939 AssertRCReturn(rc, rc);
4940# else
4941 rc = AudioMixerCreateSink(pThisCC->pMixer, "PCM Output",
4942 PDMAUDIODIR_OUT, pDevIns, &pThisCC->SinkFront.pMixSink);
4943 AssertRCReturn(rc, rc);
4944# endif /* VBOX_WITH_AUDIO_HDA_51_SURROUND */
4945
4946 /*
4947 * Add mixer input sinks.
4948 */
4949 rc = AudioMixerCreateSink(pThisCC->pMixer, "Line In",
4950 PDMAUDIODIR_IN, pDevIns, &pThisCC->SinkLineIn.pMixSink);
4951 AssertRCReturn(rc, rc);
4952# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
4953 rc = AudioMixerCreateSink(pThisCC->pMixer, "Microphone In",
4954 PDMAUDIODIR_IN, pDevIns, &pThisCC->SinkMicIn.pMixSink);
4955 AssertRCReturn(rc, rc);
4956# endif
4957
4958 /* There is no master volume control. Set the master to max. */
4959 PDMAUDIOVOLUME Vol = PDMAUDIOVOLUME_INITIALIZER_MAX;
4960 rc = AudioMixerSetMasterVolume(pThisCC->pMixer, &Vol);
4961 AssertRCReturn(rc, rc);
4962
4963 /*
4964 * Initialize the codec.
4965 */
4966
4967 /* Set codec callbacks to this controller. */
4968 pThisCC->Codec.pDevIns = pDevIns;
4969 pThisCC->Codec.pfnCbMixerAddStream = hdaR3MixerAddStream;
4970 pThisCC->Codec.pfnCbMixerRemoveStream = hdaR3MixerRemoveStream;
4971 pThisCC->Codec.pfnCbMixerControl = hdaR3MixerControl;
4972 pThisCC->Codec.pfnCbMixerSetVolume = hdaR3MixerSetVolume;
4973
4974 /* Construct the common + R3 codec part. */
4975 rc = hdaR3CodecConstruct(pDevIns, &pThisCC->Codec, 0 /* Codec index */, pCfg);
4976 AssertRCReturn(rc, rc);
4977
4978 /* ICH6 datasheet defines 0 values for SVID and SID (18.1.14-15), which together with values returned for
4979 verb F20 should provide device/codec recognition. */
4980 Assert(pThisCC->Codec.State.u16VendorId);
4981 Assert(pThisCC->Codec.State.u16DeviceId);
4982 PDMPciDevSetSubSystemVendorId(pPciDev, pThisCC->Codec.State.u16VendorId); /* 2c ro - intel.) */
4983 PDMPciDevSetSubSystemId( pPciDev, pThisCC->Codec.State.u16DeviceId); /* 2e ro. */
4984
4985 /*
4986 * Create the per stream timers and the asso.
4987 *
4988 * We must the critical section for the timers as the device has a
4989 * noop section associated with it.
4990 *
4991 * Note: Use TMCLOCK_VIRTUAL_SYNC here, as the guest's HDA driver relies
4992 * on exact (virtual) DMA timing and uses DMA Position Buffers
4993 * instead of the LPIB registers.
4994 */
4995 /** @todo r=bird: The need to use virtual sync is perhaps because TM
4996 * doesn't schedule regular TMCLOCK_VIRTUAL timers as accurately as it
4997 * should (VT-x preemption timer, etc). Hope to address that before
4998 * long. @bugref{9943}. */
4999 static const char * const s_apszNames[] =
5000 { "HDA SD0", "HDA SD1", "HDA SD2", "HDA SD3", "HDA SD4", "HDA SD5", "HDA SD6", "HDA SD7", };
5001 AssertCompile(RT_ELEMENTS(s_apszNames) == HDA_MAX_STREAMS);
5002 for (size_t i = 0; i < HDA_MAX_STREAMS; i++)
5003 {
5004 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hdaR3Timer, (void *)(uintptr_t)i,
5005 TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_RING0, s_apszNames[i], &pThis->aStreams[i].hTimer);
5006 AssertRCReturn(rc, rc);
5007
5008 rc = PDMDevHlpTimerSetCritSect(pDevIns, pThis->aStreams[i].hTimer, &pThis->CritSect);
5009 AssertRCReturn(rc, rc);
5010 }
5011
5012 /*
5013 * Create all hardware streams.
5014 */
5015 for (uint8_t i = 0; i < HDA_MAX_STREAMS; ++i)
5016 {
5017 rc = hdaR3StreamConstruct(&pThis->aStreams[i], &pThisCC->aStreams[i], pThis, pThisCC, i /* u8SD */);
5018 AssertRCReturn(rc, rc);
5019 }
5020
5021 hdaR3Reset(pDevIns);
5022
5023 /*
5024 * Info items and string formatter types. The latter is non-optional as
5025 * the info handles use (at least some of) the custom types and we cannot
5026 * accept screwing formatting.
5027 */
5028 PDMDevHlpDBGFInfoRegister(pDevIns, "hda", "HDA registers. (hda [register case-insensitive])", hdaR3DbgInfo);
5029 PDMDevHlpDBGFInfoRegister(pDevIns, "hdabdl",
5030 "HDA buffer descriptor list (BDL) and DMA stream positions. (hdabdl [stream number])",
5031 hdaR3DbgInfoBDL);
5032 PDMDevHlpDBGFInfoRegister(pDevIns, "hdastream", "HDA stream info. (hdastream [stream number])", hdaR3DbgInfoStream);
5033 PDMDevHlpDBGFInfoRegister(pDevIns, "hdcnodes", "HDA codec nodes.", hdaR3DbgInfoCodecNodes);
5034 PDMDevHlpDBGFInfoRegister(pDevIns, "hdcselector", "HDA codec's selector states [node number].", hdaR3DbgInfoCodecSelector);
5035 PDMDevHlpDBGFInfoRegister(pDevIns, "hdamixer", "HDA mixer state.", hdaR3DbgInfoMixer);
5036
5037 rc = RTStrFormatTypeRegister("sdctl", hdaR3StrFmtSDCTL, NULL);
5038 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5039 rc = RTStrFormatTypeRegister("sdsts", hdaR3StrFmtSDSTS, NULL);
5040 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5041 /** @todo the next two are rather pointless. */
5042 rc = RTStrFormatTypeRegister("sdfifos", hdaR3StrFmtSDFIFOS, NULL);
5043 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5044 rc = RTStrFormatTypeRegister("sdfifow", hdaR3StrFmtSDFIFOW, NULL);
5045 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5046
5047 /*
5048 * Asserting sanity.
5049 */
5050 AssertCompile(RT_ELEMENTS(pThis->au32Regs) < 256 /* assumption by HDAREGDESC::idxReg */);
5051 for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
5052 {
5053 struct HDAREGDESC const *pReg = &g_aHdaRegMap[i];
5054 struct HDAREGDESC const *pNextReg = i + 1 < RT_ELEMENTS(g_aHdaRegMap) ? &g_aHdaRegMap[i + 1] : NULL;
5055
5056 /* binary search order. */
5057 AssertReleaseMsg(!pNextReg || pReg->off + pReg->cb <= pNextReg->off,
5058 ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
5059 i, pReg->off, pReg->cb, i + 1, pNextReg->off, pNextReg->cb));
5060
5061 /* alignment. */
5062 AssertReleaseMsg( pReg->cb == 1
5063 || (pReg->cb == 2 && (pReg->off & 1) == 0)
5064 || (pReg->cb == 3 && (pReg->off & 3) == 0)
5065 || (pReg->cb == 4 && (pReg->off & 3) == 0),
5066 ("[%#x] = {%#x LB %#x}\n", i, pReg->off, pReg->cb));
5067
5068 /* registers are packed into dwords - with 3 exceptions with gaps at the end of the dword. */
5069 AssertRelease(((pReg->off + pReg->cb) & 3) == 0 || pNextReg);
5070 if (pReg->off & 3)
5071 {
5072 struct HDAREGDESC const *pPrevReg = i > 0 ? &g_aHdaRegMap[i - 1] : NULL;
5073 AssertReleaseMsg(pPrevReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->off, pReg->cb));
5074 if (pPrevReg)
5075 AssertReleaseMsg(pPrevReg->off + pPrevReg->cb == pReg->off,
5076 ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
5077 i - 1, pPrevReg->off, pPrevReg->cb, i + 1, pReg->off, pReg->cb));
5078 }
5079#if 0
5080 if ((pReg->offset + pReg->size) & 3)
5081 {
5082 AssertReleaseMsg(pNextReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
5083 if (pNextReg)
5084 AssertReleaseMsg(pReg->offset + pReg->size == pNextReg->offset,
5085 ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
5086 i, pReg->offset, pReg->size, i + 1, pNextReg->offset, pNextReg->size));
5087 }
5088#endif
5089 /* The final entry is a full DWORD, no gaps! Allows shortcuts. */
5090 AssertReleaseMsg(pNextReg || ((pReg->off + pReg->cb) & 3) == 0,
5091 ("[%#x] = {%#x LB %#x}\n", i, pReg->off, pReg->cb));
5092 }
5093
5094# ifdef VBOX_WITH_STATISTICS
5095 /*
5096 * Register statistics.
5097 */
5098 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn, STAMTYPE_PROFILE, "Input", STAMUNIT_TICKS_PER_CALL, "Profiling input.");
5099 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatOut, STAMTYPE_PROFILE, "Output", STAMUNIT_TICKS_PER_CALL, "Profiling output.");
5100 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, "BytesRead" , STAMUNIT_BYTES, "Bytes read (DMA) from the guest.");
5101 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "BytesWritten", STAMUNIT_BYTES, "Bytes written (DMA) to the guest.");
5102# ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
5103 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatAccessDmaOutput, STAMTYPE_COUNTER, "AccessDmaOutput", STAMUNIT_COUNT, "Number of on-register-access DMA sub-transfers we've made.");
5104 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatAccessDmaOutputToR3,STAMTYPE_COUNTER, "AccessDmaOutputToR3", STAMUNIT_COUNT, "Number of time the on-register-access DMA forced a ring-3 return.");
5105# endif
5106
5107 AssertCompile(RT_ELEMENTS(g_aHdaRegMap) == HDA_NUM_REGS);
5108 AssertCompile(RT_ELEMENTS(pThis->aStatRegReads) == HDA_NUM_REGS);
5109 AssertCompile(RT_ELEMENTS(pThis->aStatRegReadsToR3) == HDA_NUM_REGS);
5110 AssertCompile(RT_ELEMENTS(pThis->aStatRegWrites) == HDA_NUM_REGS);
5111 AssertCompile(RT_ELEMENTS(pThis->aStatRegWritesToR3) == HDA_NUM_REGS);
5112 for (size_t i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
5113 {
5114 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegReads[i], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
5115 g_aHdaRegMap[i].pszDesc, "Regs/%03x-%s-Reads", g_aHdaRegMap[i].off, g_aHdaRegMap[i].pszName);
5116 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegReadsToR3[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5117 g_aHdaRegMap[i].pszDesc, "Regs/%03x-%s-Reads-ToR3", g_aHdaRegMap[i].off, g_aHdaRegMap[i].pszName);
5118 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegWrites[i], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
5119 g_aHdaRegMap[i].pszDesc, "Regs/%03x-%s-Writes", g_aHdaRegMap[i].off, g_aHdaRegMap[i].pszName);
5120 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegWritesToR3[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5121 g_aHdaRegMap[i].pszDesc, "Regs/%03x-%s-Writes-ToR3", g_aHdaRegMap[i].off, g_aHdaRegMap[i].pszName);
5122 }
5123 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiReadsR3, STAMTYPE_COUNTER, "RegMultiReadsR3", STAMUNIT_OCCURENCES, "Register read not targeting just one register, handled in ring-3");
5124 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiReadsRZ, STAMTYPE_COUNTER, "RegMultiReadsRZ", STAMUNIT_OCCURENCES, "Register read not targeting just one register, handled in ring-0");
5125 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiWritesR3, STAMTYPE_COUNTER, "RegMultiWritesR3", STAMUNIT_OCCURENCES, "Register writes not targeting just one register, handled in ring-3");
5126 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiWritesRZ, STAMTYPE_COUNTER, "RegMultiWritesRZ", STAMUNIT_OCCURENCES, "Register writes not targeting just one register, handled in ring-0");
5127 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegSubWriteR3, STAMTYPE_COUNTER, "RegSubWritesR3", STAMUNIT_OCCURENCES, "Trucated register writes, handled in ring-3");
5128 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegSubWriteRZ, STAMTYPE_COUNTER, "RegSubWritesRZ", STAMUNIT_OCCURENCES, "Trucated register writes, handled in ring-0");
5129 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegUnknownReads, STAMTYPE_COUNTER, "RegUnknownReads", STAMUNIT_OCCURENCES, "Reads of unknown registers.");
5130 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegUnknownWrites, STAMTYPE_COUNTER, "RegUnknownWrites", STAMUNIT_OCCURENCES, "Writes to unknown registers.");
5131 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegWritesBlockedByReset, STAMTYPE_COUNTER, "RegWritesBlockedByReset", STAMUNIT_OCCURENCES, "Writes blocked by pending reset (GCTL/CRST)");
5132 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegWritesBlockedByRun, STAMTYPE_COUNTER, "RegWritesBlockedByRun", STAMUNIT_OCCURENCES, "Writes blocked by byte RUN bit.");
5133# endif
5134
5135 for (uint8_t idxStream = 0; idxStream < RT_ELEMENTS(pThisCC->aStreams); idxStream++)
5136 {
5137 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowProblems, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5138 "Number of internal DMA buffer problems.", "Stream%u/DMABufferProblems", idxStream);
5139 if (hdaGetDirFromSD(idxStream) == PDMAUDIODIR_OUT)
5140 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5141 "Number of internal DMA buffer overflows.", "Stream%u/DMABufferOverflows", idxStream);
5142 else
5143 {
5144 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5145 "Number of internal DMA buffer underuns.", "Stream%u/DMABufferUnderruns", idxStream);
5146 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrorBytes, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5147 "Number of bytes of silence added to cope with underruns.", "Stream%u/DMABufferSilence", idxStream);
5148 }
5149 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaSkippedPendingBcis, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5150 "DMA transfer period skipped because of BCIS pending.", "Stream%u/DMASkippedPendingBCIS", idxStream);
5151
5152 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.offRead, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5153 "Virtual internal buffer read position.", "Stream%u/offRead", idxStream);
5154 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.offWrite, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5155 "Virtual internal buffer write position.", "Stream%u/offWrite", idxStream);
5156 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.cbCurDmaPeriod, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5157 "Bytes transfered per DMA timer callout.", "Stream%u/cbCurDmaPeriod", idxStream);
5158 PDMDevHlpSTAMRegisterF(pDevIns, (void*)&pThis->aStreams[idxStream].State.fRunning, STAMTYPE_BOOL, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5159 "True if the stream is in RUN mode.", "Stream%u/fRunning", idxStream);
5160 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.uHz, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_HZ,
5161 "The stream frequency.", "Stream%u/Cfg/Hz", idxStream);
5162 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cbFrame, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5163 "The frame size.", "Stream%u/Cfg/FrameSize", idxStream);
5164#if 0 /** @todo this would require some callback or expansion. */
5165 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cChannelsX, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5166 "The number of channels.", "Stream%u/Cfg/Channels-Host", idxStream);
5167 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.Mapping.GuestProps.cChannels, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5168 "The number of channels.", "Stream%u/Cfg/Channels-Guest", idxStream);
5169 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cbSample, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5170 "The size of a sample (per channel).", "Stream%u/Cfg/cbSample", idxStream);
5171#endif
5172
5173 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaBufSize, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5174 "Size of the internal DMA buffer.", "Stream%u/DMABufSize", idxStream);
5175 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaBufUsed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5176 "Number of bytes used in the internal DMA buffer.", "Stream%u/DMABufUsed", idxStream);
5177
5178 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatStart, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
5179 "Starting the stream.", "Stream%u/Start", idxStream);
5180 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatStop, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
5181 "Stopping the stream.", "Stream%u/Stop", idxStream);
5182 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatReset, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
5183 "Resetting the stream.", "Stream%u/Reset", idxStream);
5184 }
5185
5186 return VINF_SUCCESS;
5187}
5188
5189#else /* !IN_RING3 */
5190
5191/**
5192 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
5193 */
5194static DECLCALLBACK(int) hdaRZConstruct(PPDMDEVINS pDevIns)
5195{
5196 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* this shall come first */
5197 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
5198 PHDASTATER0 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER0);
5199
5200 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
5201 AssertRCReturn(rc, rc);
5202
5203 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, hdaMmioWrite, hdaMmioRead, NULL /*pvUser*/);
5204 AssertRCReturn(rc, rc);
5205
5206# if 0 /* Codec is not yet kosher enough for ring-0. @bugref{9890c64} */
5207 /* Construct the R0 codec part. */
5208 rc = hdaR0CodecConstruct(pDevIns, &pThis->Codec, &pThisCC->Codec);
5209 AssertRCReturn(rc, rc);
5210# else
5211 RT_NOREF(pThisCC);
5212# endif
5213
5214 return VINF_SUCCESS;
5215}
5216
5217#endif /* !IN_RING3 */
5218
5219/**
5220 * The device registration structure.
5221 */
5222const PDMDEVREG g_DeviceHDA =
5223{
5224 /* .u32Version = */ PDM_DEVREG_VERSION,
5225 /* .uReserved0 = */ 0,
5226 /* .szName = */ "hda",
5227 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
5228 | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION /* stream clearnup with working drivers */,
5229 /* .fClass = */ PDM_DEVREG_CLASS_AUDIO,
5230 /* .cMaxInstances = */ 1,
5231 /* .uSharedVersion = */ 42,
5232 /* .cbInstanceShared = */ sizeof(HDASTATE),
5233 /* .cbInstanceCC = */ CTX_EXPR(sizeof(HDASTATER3), sizeof(HDASTATER0), 0),
5234 /* .cbInstanceRC = */ 0,
5235 /* .cMaxPciDevices = */ 1,
5236 /* .cMaxMsixVectors = */ 0,
5237 /* .pszDescription = */ "Intel HD Audio Controller",
5238#if defined(IN_RING3)
5239 /* .pszRCMod = */ "VBoxDDRC.rc",
5240 /* .pszR0Mod = */ "VBoxDDR0.r0",
5241 /* .pfnConstruct = */ hdaR3Construct,
5242 /* .pfnDestruct = */ hdaR3Destruct,
5243 /* .pfnRelocate = */ NULL,
5244 /* .pfnMemSetup = */ NULL,
5245 /* .pfnPowerOn = */ NULL,
5246 /* .pfnReset = */ hdaR3Reset,
5247 /* .pfnSuspend = */ NULL,
5248 /* .pfnResume = */ NULL,
5249 /* .pfnAttach = */ hdaR3Attach,
5250 /* .pfnDetach = */ hdaR3Detach,
5251 /* .pfnQueryInterface = */ NULL,
5252 /* .pfnInitComplete = */ NULL,
5253 /* .pfnPowerOff = */ hdaR3PowerOff,
5254 /* .pfnSoftReset = */ NULL,
5255 /* .pfnReserved0 = */ NULL,
5256 /* .pfnReserved1 = */ NULL,
5257 /* .pfnReserved2 = */ NULL,
5258 /* .pfnReserved3 = */ NULL,
5259 /* .pfnReserved4 = */ NULL,
5260 /* .pfnReserved5 = */ NULL,
5261 /* .pfnReserved6 = */ NULL,
5262 /* .pfnReserved7 = */ NULL,
5263#elif defined(IN_RING0)
5264 /* .pfnEarlyConstruct = */ NULL,
5265 /* .pfnConstruct = */ hdaRZConstruct,
5266 /* .pfnDestruct = */ NULL,
5267 /* .pfnFinalDestruct = */ NULL,
5268 /* .pfnRequest = */ NULL,
5269 /* .pfnReserved0 = */ NULL,
5270 /* .pfnReserved1 = */ NULL,
5271 /* .pfnReserved2 = */ NULL,
5272 /* .pfnReserved3 = */ NULL,
5273 /* .pfnReserved4 = */ NULL,
5274 /* .pfnReserved5 = */ NULL,
5275 /* .pfnReserved6 = */ NULL,
5276 /* .pfnReserved7 = */ NULL,
5277#elif defined(IN_RC)
5278 /* .pfnConstruct = */ hdaRZConstruct,
5279 /* .pfnReserved0 = */ NULL,
5280 /* .pfnReserved1 = */ NULL,
5281 /* .pfnReserved2 = */ NULL,
5282 /* .pfnReserved3 = */ NULL,
5283 /* .pfnReserved4 = */ NULL,
5284 /* .pfnReserved5 = */ NULL,
5285 /* .pfnReserved6 = */ NULL,
5286 /* .pfnReserved7 = */ NULL,
5287#else
5288# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5289#endif
5290 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
5291};
5292
5293#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
5294
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette