VirtualBox

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

Last change on this file since 90137 was 90137, checked in by vboxsync, 3 years ago

DevHda: Don't pass pDevIns but PHDACODECR3 to the four DevHDA functions the codec calls. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 214.0 KB
Line 
1/* $Id: DevHda.cpp 90137 2021-07-09 20:48:35Z 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 = hdaR3CodecLookup(&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 = hdaR3CodecLookup(&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/**
2593 * Adds a new audio stream to a specific mixer control.
2594 *
2595 * Depending on the mixer control the stream then gets assigned to one of the
2596 * internal mixer sinks, which in turn then handle the mixing of all connected
2597 * streams to that sink.
2598 *
2599 * @return VBox status code.
2600 * @param pCodec The codec instance data.
2601 * @param enmMixerCtl Mixer control to assign new stream to.
2602 * @param pCfg Stream configuration for the new stream.
2603 */
2604DECLHIDDEN(int) hdaR3MixerAddStream(PHDACODECR3 pCodec, PDMAUDIOMIXERCTL enmMixerCtl, PCPDMAUDIOSTREAMCFG pCfg)
2605{
2606 PHDASTATER3 pThisCC = RT_FROM_MEMBER(pCodec, HDASTATER3, Codec);
2607 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2608
2609 int rc;
2610 PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThisCC, enmMixerCtl);
2611 if (pSink)
2612 {
2613 rc = hdaR3MixerAddDrvStreams(pThisCC->pDevIns, pThisCC, pSink->pMixSink, pCfg);
2614
2615 AssertPtr(pSink->pMixSink);
2616 LogFlowFunc(("Sink=%s, Mixer control=%s\n", pSink->pMixSink->pszName, PDMAudioMixerCtlGetName(enmMixerCtl)));
2617 }
2618 else
2619 rc = VERR_NOT_FOUND;
2620
2621 LogFlowFuncLeaveRC(rc);
2622 return rc;
2623}
2624
2625/**
2626 * Removes a specified mixer control from the HDA's mixer.
2627 *
2628 * @return VBox status code.
2629 * @param pCodec The codec instance data.
2630 * @param enmMixerCtl Mixer control to remove.
2631 * @param fImmediate Whether the backend should be allowed to
2632 * finished draining (@c false) or if it must be
2633 * destroyed immediately (@c true).
2634 */
2635DECLHIDDEN(int) hdaR3MixerRemoveStream(PHDACODECR3 pCodec, PDMAUDIOMIXERCTL enmMixerCtl, bool fImmediate)
2636{
2637 PHDASTATER3 pThisCC = RT_FROM_MEMBER(pCodec, HDASTATER3, Codec);
2638 int rc;
2639
2640 PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThisCC, enmMixerCtl);
2641 if (pSink)
2642 {
2643 PHDADRIVER pDrv;
2644 RTListForEach(&pThisCC->lstDrv, pDrv, HDADRIVER, Node)
2645 {
2646 PAUDMIXSTREAM pMixStream = NULL;
2647 switch (enmMixerCtl)
2648 {
2649 /*
2650 * Input.
2651 */
2652 case PDMAUDIOMIXERCTL_LINE_IN:
2653 pMixStream = pDrv->LineIn.pMixStrm;
2654 pDrv->LineIn.pMixStrm = NULL;
2655 break;
2656# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2657 case PDMAUDIOMIXERCTL_MIC_IN:
2658 pMixStream = pDrv->MicIn.pMixStrm;
2659 pDrv->MicIn.pMixStrm = NULL;
2660 break;
2661# endif
2662 /*
2663 * Output.
2664 */
2665 case PDMAUDIOMIXERCTL_FRONT:
2666 pMixStream = pDrv->Front.pMixStrm;
2667 pDrv->Front.pMixStrm = NULL;
2668 break;
2669# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2670 case PDMAUDIOMIXERCTL_CENTER_LFE:
2671 pMixStream = pDrv->CenterLFE.pMixStrm;
2672 pDrv->CenterLFE.pMixStrm = NULL;
2673 break;
2674 case PDMAUDIOMIXERCTL_REAR:
2675 pMixStream = pDrv->Rear.pMixStrm;
2676 pDrv->Rear.pMixStrm = NULL;
2677 break;
2678# endif
2679 default:
2680 AssertMsgFailed(("Mixer control %d not implemented\n", enmMixerCtl));
2681 break;
2682 }
2683
2684 if (pMixStream)
2685 {
2686 AudioMixerSinkRemoveStream(pSink->pMixSink, pMixStream);
2687 AudioMixerStreamDestroy(pMixStream, pThisCC->pDevIns, fImmediate);
2688
2689 pMixStream = NULL;
2690 }
2691 }
2692
2693 AudioMixerSinkRemoveAllStreams(pSink->pMixSink);
2694 rc = VINF_SUCCESS;
2695 }
2696 else
2697 rc = VERR_NOT_FOUND;
2698
2699 LogFunc(("Mixer control=%s, rc=%Rrc\n", PDMAudioMixerCtlGetName(enmMixerCtl), rc));
2700 return rc;
2701}
2702
2703/**
2704 * Controls an input / output converter widget, that is, which converter is
2705 * connected to which stream (and channel).
2706 *
2707 * @return VBox status code.
2708 * @param pCodec The codec instance data.
2709 * @param enmMixerCtl Mixer control to set SD stream number and channel for.
2710 * @param uSD SD stream number (number + 1) to set. Set to 0 for unassign.
2711 * @param uChannel Channel to set. Only valid if a valid SD stream number is specified.
2712 *
2713 * @note Is also called directly by the DevHDA code.
2714 */
2715DECLHIDDEN(int) hdaR3MixerControl(PHDACODECR3 pCodec, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel)
2716{
2717 PHDASTATER3 pThisCC = RT_FROM_MEMBER(pCodec, HDASTATER3, Codec);
2718 PHDASTATE pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PHDASTATE);
2719 LogFunc(("enmMixerCtl=%s, uSD=%RU8, uChannel=%RU8\n", PDMAudioMixerCtlGetName(enmMixerCtl), uSD, uChannel));
2720
2721 if (uSD == 0) /* Stream number 0 is reserved. */
2722 {
2723 Log2Func(("Invalid SDn (%RU8) number for mixer control '%s', ignoring\n", uSD, PDMAudioMixerCtlGetName(enmMixerCtl)));
2724 return VINF_SUCCESS;
2725 }
2726 /* uChannel is optional. */
2727
2728 /* SDn0 starts as 1. */
2729 Assert(uSD);
2730 uSD--;
2731
2732# ifndef VBOX_WITH_AUDIO_HDA_MIC_IN
2733 /* Only SDI0 (Line-In) is supported. */
2734 if ( hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN
2735 && uSD >= 1)
2736 {
2737 LogRel2(("HDA: Dedicated Mic-In support not imlpemented / built-in (stream #%RU8), using Line-In (stream #0) instead\n", uSD));
2738 uSD = 0;
2739 }
2740# endif
2741
2742 int rc = VINF_SUCCESS;
2743
2744 PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThisCC, enmMixerCtl);
2745 if (pSink)
2746 {
2747 AssertPtr(pSink->pMixSink);
2748
2749 /* If this an output stream, determine the correct SD#. */
2750 if ( uSD < HDA_MAX_SDI
2751 && AudioMixerSinkGetDir(pSink->pMixSink) == PDMAUDIODIR_OUT)
2752 uSD += HDA_MAX_SDI;
2753
2754 /* Make 100% sure we got a good stream number before continuing. */
2755 AssertLogRelReturn(uSD < RT_ELEMENTS(pThisCC->aStreams), VERR_NOT_IMPLEMENTED);
2756
2757 /* Detach the existing stream from the sink. */
2758 PHDASTREAM const pOldStreamShared = pSink->pStreamShared;
2759 PHDASTREAMR3 const pOldStreamR3 = pSink->pStreamR3;
2760 if ( pOldStreamShared
2761 && pOldStreamR3
2762 && ( pOldStreamShared->u8SD != uSD
2763 || pOldStreamShared->u8Channel != uChannel)
2764 )
2765 {
2766 LogFunc(("Sink '%s' was assigned to stream #%RU8 (channel %RU8) before\n",
2767 pSink->pMixSink->pszName, pOldStreamShared->u8SD, pOldStreamShared->u8Channel));
2768 Assert(PDMCritSectIsOwner(&pThis->CritSect));
2769
2770 /* Only disable the stream if the stream descriptor # has changed. */
2771 if (pOldStreamShared->u8SD != uSD)
2772 hdaR3StreamEnable(pThis, pOldStreamShared, pOldStreamR3, false /*fEnable*/);
2773
2774 if (pOldStreamR3->State.pAioRegSink)
2775 {
2776 AudioMixerSinkRemoveUpdateJob(pOldStreamR3->State.pAioRegSink, hdaR3StreamUpdateAsyncIoJob, pOldStreamR3);
2777 pOldStreamR3->State.pAioRegSink = NULL;
2778 }
2779
2780 pOldStreamR3->pMixSink = NULL;
2781
2782
2783 pSink->pStreamShared = NULL;
2784 pSink->pStreamR3 = NULL;
2785 }
2786
2787 /* Attach the new stream to the sink.
2788 * Enabling the stream will be done by the guest via a separate SDnCTL call then. */
2789 if (pSink->pStreamShared == NULL)
2790 {
2791 LogRel2(("HDA: Setting sink '%s' to stream #%RU8 (channel %RU8), mixer control=%s\n",
2792 pSink->pMixSink->pszName, uSD, uChannel, PDMAudioMixerCtlGetName(enmMixerCtl)));
2793
2794 PHDASTREAMR3 pStreamR3 = &pThisCC->aStreams[uSD];
2795 PHDASTREAM pStreamShared = &pThis->aStreams[uSD];
2796 Assert(PDMCritSectIsOwner(&pThis->CritSect));
2797
2798 pSink->pStreamR3 = pStreamR3;
2799 pSink->pStreamShared = pStreamShared;
2800
2801 pStreamShared->u8Channel = uChannel;
2802 pStreamR3->pMixSink = pSink;
2803
2804 rc = VINF_SUCCESS;
2805 }
2806 }
2807 else
2808 rc = VERR_NOT_FOUND;
2809
2810 if (RT_FAILURE(rc))
2811 LogRel(("HDA: Converter control for stream #%RU8 (channel %RU8) / mixer control '%s' failed with %Rrc, skipping\n",
2812 uSD, uChannel, PDMAudioMixerCtlGetName(enmMixerCtl), rc));
2813
2814 LogFlowFuncLeaveRC(rc);
2815 return rc;
2816}
2817
2818/**
2819 * Sets the volume of a specified mixer control.
2820 *
2821 * @return IPRT status code.
2822 * @param pCodec The codec instance data.
2823 * @param enmMixerCtl Mixer control to set volume for.
2824 * @param pVol Pointer to volume data to set.
2825 */
2826DECLHIDDEN(int) hdaR3MixerSetVolume(PHDACODECR3 pCodec, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOVOLUME pVol)
2827{
2828 PHDASTATER3 pThisCC = RT_FROM_MEMBER(pCodec, HDASTATER3, Codec);
2829 int rc;
2830
2831 PHDAMIXERSINK pSink = hdaR3MixerControlToSink(pThisCC, enmMixerCtl);
2832 if ( pSink
2833 && pSink->pMixSink)
2834 {
2835 LogRel2(("HDA: Setting volume for mixer sink '%s' to fMuted=%RTbool auChannels=%.*Rhxs\n",
2836 pSink->pMixSink->pszName, pVol->fMuted, sizeof(pVol->auChannels), pVol->auChannels));
2837
2838 /* Set the volume.
2839 * We assume that the codec already converted it to the correct range. */
2840 rc = AudioMixerSinkSetVolume(pSink->pMixSink, pVol);
2841 }
2842 else
2843 rc = VERR_NOT_FOUND;
2844
2845 LogFlowFuncLeaveRC(rc);
2846 return rc;
2847}
2848
2849/**
2850 * @callback_method_impl{FNTMTIMERDEV, Main routine for the stream's timer.}
2851 */
2852static DECLCALLBACK(void) hdaR3Timer(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)
2853{
2854 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
2855 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
2856 uintptr_t idxStream = (uintptr_t)pvUser;
2857 AssertReturnVoid(idxStream < RT_ELEMENTS(pThis->aStreams));
2858 PHDASTREAM pStreamShared = &pThis->aStreams[idxStream];
2859 PHDASTREAMR3 pStreamR3 = &pThisCC->aStreams[idxStream];
2860 Assert(hTimer == pStreamShared->hTimer);
2861
2862 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
2863 Assert(PDMDevHlpTimerIsLockOwner(pDevIns, hTimer));
2864
2865 RT_NOREF(hTimer);
2866
2867 hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
2868}
2869
2870/**
2871 * Soft reset of the device triggered via GCTL.
2872 *
2873 * @param pDevIns The device instance.
2874 * @param pThis The shared HDA device state.
2875 * @param pThisCC The ring-3 HDA device state.
2876 */
2877static void hdaR3GCTLReset(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC)
2878{
2879 LogFlowFuncEnter();
2880 Assert(PDMCritSectIsOwner(&pThis->CritSect));
2881
2882 /*
2883 * Make sure all streams have stopped as these have both timers and
2884 * asynchronous worker threads that would race us if we delay this work.
2885 */
2886 for (size_t idxStream = 0; idxStream < RT_ELEMENTS(pThis->aStreams); idxStream++)
2887 {
2888 PHDASTREAM const pStreamShared = &pThis->aStreams[idxStream];
2889 PHDASTREAMR3 const pStreamR3 = &pThisCC->aStreams[idxStream];
2890 PAUDMIXSINK const pMixSink = pStreamR3->pMixSink ? pStreamR3->pMixSink->pMixSink : NULL;
2891 if (pMixSink)
2892 AudioMixerSinkLock(pMixSink);
2893
2894 /* We're doing this unconditionally, hope that's not problematic in any way... */
2895 int rc = hdaR3StreamEnable(pThis, pStreamShared, &pThisCC->aStreams[idxStream], false /* fEnable */);
2896 AssertLogRelMsg(RT_SUCCESS(rc) && !pStreamShared->State.fRunning,
2897 ("Disabling stream #%u failed: %Rrc, fRunning=%d\n", idxStream, rc, pStreamShared->State.fRunning));
2898 pStreamShared->State.fRunning = false;
2899
2900 hdaR3StreamReset(pThis, pThisCC, pStreamShared, &pThisCC->aStreams[idxStream], (uint8_t)idxStream);
2901
2902 if (pMixSink) /* (FYI. pMixSink might not be what pStreamR3->pMixSink->pMixSink points at any longer) */
2903 AudioMixerSinkUnlock(pMixSink);
2904 }
2905
2906 /*
2907 * Reset registers.
2908 */
2909 HDA_REG(pThis, GCAP) = HDA_MAKE_GCAP(HDA_MAX_SDO, HDA_MAX_SDI, 0, 0, 1); /* see 6.2.1 */
2910 HDA_REG(pThis, VMIN) = 0x00; /* see 6.2.2 */
2911 HDA_REG(pThis, VMAJ) = 0x01; /* see 6.2.3 */
2912 HDA_REG(pThis, OUTPAY) = 0x003C; /* see 6.2.4 */
2913 HDA_REG(pThis, INPAY) = 0x001D; /* see 6.2.5 */
2914 HDA_REG(pThis, CORBSIZE) = 0x42; /* Up to 256 CORB entries see 6.2.1 */
2915 HDA_REG(pThis, RIRBSIZE) = 0x42; /* Up to 256 RIRB entries see 6.2.1 */
2916 HDA_REG(pThis, CORBRP) = 0x0;
2917 HDA_REG(pThis, CORBWP) = 0x0;
2918 HDA_REG(pThis, RIRBWP) = 0x0;
2919 /* Some guests (like Haiku) don't set RINTCNT explicitly but expect an interrupt after each
2920 * RIRB response -- so initialize RINTCNT to 1 by default. */
2921 HDA_REG(pThis, RINTCNT) = 0x1;
2922
2923 /*
2924 * Stop any audio currently playing and/or recording.
2925 */
2926 pThisCC->SinkFront.pStreamShared = NULL;
2927 pThisCC->SinkFront.pStreamR3 = NULL;
2928 if (pThisCC->SinkFront.pMixSink)
2929 AudioMixerSinkReset(pThisCC->SinkFront.pMixSink);
2930# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2931 pThisCC->SinkMicIn.pStreamShared = NULL;
2932 pThisCC->SinkMicIn.pStreamR3 = NULL;
2933 if (pThisCC->SinkMicIn.pMixSink)
2934 AudioMixerSinkReset(pThisCC->SinkMicIn.pMixSink);
2935# endif
2936 pThisCC->SinkLineIn.pStreamShared = NULL;
2937 pThisCC->SinkLineIn.pStreamR3 = NULL;
2938 if (pThisCC->SinkLineIn.pMixSink)
2939 AudioMixerSinkReset(pThisCC->SinkLineIn.pMixSink);
2940# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2941 pThisCC->SinkCenterLFE = NULL;
2942 if (pThisCC->SinkCenterLFE.pMixSink)
2943 AudioMixerSinkReset(pThisCC->SinkCenterLFE.pMixSink);
2944 pThisCC->SinkRear.pStreamShared = NULL;
2945 pThisCC->SinkRear.pStreamR3 = NULL;
2946 if (pThisCC->SinkRear.pMixSink)
2947 AudioMixerSinkReset(pThisCC->SinkRear.pMixSink);
2948# endif
2949
2950 /*
2951 * Reset the codec.
2952 */
2953 hdaCodecReset(&pThisCC->Codec);
2954
2955 /*
2956 * Set some sensible defaults for which HDA sinks
2957 * are connected to which stream number.
2958 *
2959 * We use SD0 for input and SD4 for output by default.
2960 * These stream numbers can be changed by the guest dynamically lateron.
2961 */
2962 ASMCompilerBarrier(); /* paranoia */
2963# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2964 hdaR3MixerControl(&pThisCC->Codec, PDMAUDIOMIXERCTL_MIC_IN , 1 /* SD0 */, 0 /* Channel */);
2965# endif
2966 hdaR3MixerControl(&pThisCC->Codec, PDMAUDIOMIXERCTL_LINE_IN , 1 /* SD0 */, 0 /* Channel */);
2967
2968 hdaR3MixerControl(&pThisCC->Codec, PDMAUDIOMIXERCTL_FRONT , 5 /* SD4 */, 0 /* Channel */);
2969# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2970 hdaR3MixerControl(&pThisCC->Codec, PDMAUDIOMIXERCTL_CENTER_LFE, 5 /* SD4 */, 0 /* Channel */);
2971 hdaR3MixerControl(&pThisCC->Codec, PDMAUDIOMIXERCTL_REAR , 5 /* SD4 */, 0 /* Channel */);
2972# endif
2973 ASMCompilerBarrier(); /* paranoia */
2974
2975 /* Reset CORB. */
2976 pThis->cbCorbBuf = HDA_CORB_SIZE * HDA_CORB_ELEMENT_SIZE;
2977 RT_ZERO(pThis->au32CorbBuf);
2978
2979 /* Reset RIRB. */
2980 pThis->cbRirbBuf = HDA_RIRB_SIZE * HDA_RIRB_ELEMENT_SIZE;
2981 RT_ZERO(pThis->au64RirbBuf);
2982
2983 /* Clear our internal response interrupt counter. */
2984 pThis->u16RespIntCnt = 0;
2985
2986 /* Clear stream tags <-> objects mapping table. */
2987 RT_ZERO(pThisCC->aTags);
2988
2989 /* Emulation of codec "wake up" (HDA spec 5.5.1 and 6.5). */
2990 HDA_REG(pThis, STATESTS) = 0x1;
2991
2992 /* Reset the wall clock. */
2993 pThis->tsWalClkStart = PDMDevHlpTimerGet(pDevIns, pThis->aStreams[0].hTimer);
2994
2995 LogFlowFuncLeave();
2996 LogRel(("HDA: Reset\n"));
2997}
2998
2999#else /* !IN_RING3 */
3000
3001/**
3002 * Checks if a dword read starting with @a idxRegDsc is safe.
3003 *
3004 * We can guarentee it only standard reader callbacks are used.
3005 * @returns true if it will always succeed, false if it may return back to
3006 * ring-3 or we're just not sure.
3007 * @param idxRegDsc The first register descriptor in the DWORD being read.
3008 */
3009DECLINLINE(bool) hdaIsMultiReadSafeInRZ(unsigned idxRegDsc)
3010{
3011 int32_t cbLeft = 4; /* signed on purpose */
3012 do
3013 {
3014 if ( g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadU24
3015 || g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadU16
3016 || g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadU8
3017 || g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadUnimpl)
3018 { /* okay */ }
3019 else
3020 {
3021 Log4(("hdaIsMultiReadSafeInRZ: idxRegDsc=%u %s\n", idxRegDsc, g_aHdaRegMap[idxRegDsc].pszName));
3022 return false;
3023 }
3024
3025 idxRegDsc++;
3026 if (idxRegDsc < RT_ELEMENTS(g_aHdaRegMap))
3027 cbLeft -= g_aHdaRegMap[idxRegDsc].off - g_aHdaRegMap[idxRegDsc - 1].off;
3028 else
3029 break;
3030 } while (cbLeft > 0);
3031 return true;
3032}
3033
3034
3035#endif /* !IN_RING3 */
3036
3037
3038/* MMIO callbacks */
3039
3040/**
3041 * @callback_method_impl{FNIOMMMIONEWREAD, Looks up and calls the appropriate handler.}
3042 *
3043 * @note During implementation, we discovered so-called "forgotten" or "hole"
3044 * registers whose description is not listed in the RPM, datasheet, or
3045 * spec.
3046 */
3047static DECLCALLBACK(VBOXSTRICTRC) hdaMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
3048{
3049 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3050 VBOXSTRICTRC rc;
3051 RT_NOREF_PV(pvUser);
3052 Assert(pThis->uAlignmentCheckMagic == HDASTATE_ALIGNMENT_CHECK_MAGIC);
3053
3054 /*
3055 * Look up and log.
3056 */
3057 int idxRegDsc = hdaRegLookup(off); /* Register descriptor index. */
3058#ifdef LOG_ENABLED
3059 unsigned const cbLog = cb;
3060 uint32_t offRegLog = (uint32_t)off;
3061# ifdef HDA_DEBUG_GUEST_RIP
3062 if (LogIs6Enabled())
3063 {
3064 PVMCPU pVCpu = (PVMCPU)PDMDevHlpGetVMCPU(pDevIns);
3065 Log6Func(("cs:rip=%04x:%016RX64 rflags=%08RX32\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu), CPUMGetGuestEFlags(pVCpu)));
3066 }
3067# endif
3068#endif
3069
3070 Log3Func(("off=%#x cb=%#x\n", offRegLog, cb));
3071 Assert(cb == 4); Assert((off & 3) == 0);
3072
3073 rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VINF_IOM_R3_MMIO_READ);
3074 if (rc == VINF_SUCCESS)
3075 {
3076 if (!(HDA_REG(pThis, GCTL) & HDA_GCTL_CRST) && idxRegDsc != HDA_REG_GCTL)
3077 LogFunc(("Access to registers except GCTL is blocked while resetting\n"));
3078
3079 if (idxRegDsc >= 0)
3080 {
3081 /* ASSUMES gapless DWORD at end of map. */
3082 if (g_aHdaRegMap[idxRegDsc].cb == 4)
3083 {
3084 /*
3085 * Straight forward DWORD access.
3086 */
3087 rc = g_aHdaRegMap[idxRegDsc].pfnRead(pDevIns, pThis, idxRegDsc, (uint32_t *)pv);
3088 Log3Func((" Read %s => %x (%Rrc)\n", g_aHdaRegMap[idxRegDsc].pszName, *(uint32_t *)pv, VBOXSTRICTRC_VAL(rc)));
3089 STAM_COUNTER_INC(&pThis->aStatRegReads[idxRegDsc]);
3090 }
3091#ifndef IN_RING3
3092 else if (!hdaIsMultiReadSafeInRZ(idxRegDsc))
3093
3094 {
3095 STAM_COUNTER_INC(&pThis->aStatRegReadsToR3[idxRegDsc]);
3096 rc = VINF_IOM_R3_MMIO_READ;
3097 }
3098#endif
3099 else
3100 {
3101 /*
3102 * Multi register read (unless there are trailing gaps).
3103 * ASSUMES that only DWORD reads have sideeffects.
3104 */
3105 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegMultiReads));
3106 Log4(("hdaMmioRead: multi read: %#x LB %#x %s\n", off, cb, g_aHdaRegMap[idxRegDsc].pszName));
3107 uint32_t u32Value = 0;
3108 unsigned cbLeft = 4;
3109 do
3110 {
3111 uint32_t const cbReg = g_aHdaRegMap[idxRegDsc].cb;
3112 uint32_t u32Tmp = 0;
3113
3114 rc = g_aHdaRegMap[idxRegDsc].pfnRead(pDevIns, pThis, idxRegDsc, &u32Tmp);
3115 Log4Func((" Read %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxRegDsc].pszName, cbReg, u32Tmp, VBOXSTRICTRC_VAL(rc)));
3116 STAM_COUNTER_INC(&pThis->aStatRegReads[idxRegDsc]);
3117#ifdef IN_RING3
3118 if (rc != VINF_SUCCESS)
3119 break;
3120#else
3121 AssertMsgBreak(rc == VINF_SUCCESS, ("rc=%Rrc - impossible, we sanitized the readers!\n", VBOXSTRICTRC_VAL(rc)));
3122#endif
3123 u32Value |= (u32Tmp & g_afMasks[cbReg]) << ((4 - cbLeft) * 8);
3124
3125 cbLeft -= cbReg;
3126 off += cbReg;
3127 idxRegDsc++;
3128 } while (cbLeft > 0 && g_aHdaRegMap[idxRegDsc].off == off);
3129
3130 if (rc == VINF_SUCCESS)
3131 *(uint32_t *)pv = u32Value;
3132 else
3133 Assert(!IOM_SUCCESS(rc));
3134 }
3135 }
3136 else
3137 {
3138 LogRel(("HDA: Invalid read access @0x%x (bytes=%u)\n", (uint32_t)off, cb));
3139 Log3Func((" Hole at %x is accessed for read\n", offRegLog));
3140 STAM_COUNTER_INC(&pThis->StatRegUnknownReads);
3141 rc = VINF_IOM_MMIO_UNUSED_FF;
3142 }
3143
3144 DEVHDA_UNLOCK(pDevIns, pThis);
3145
3146 /*
3147 * Log the outcome.
3148 */
3149#ifdef LOG_ENABLED
3150 if (cbLog == 4)
3151 Log3Func((" Returning @%#05x -> %#010x %Rrc\n", offRegLog, *(uint32_t *)pv, VBOXSTRICTRC_VAL(rc)));
3152 else if (cbLog == 2)
3153 Log3Func((" Returning @%#05x -> %#06x %Rrc\n", offRegLog, *(uint16_t *)pv, VBOXSTRICTRC_VAL(rc)));
3154 else if (cbLog == 1)
3155 Log3Func((" Returning @%#05x -> %#04x %Rrc\n", offRegLog, *(uint8_t *)pv, VBOXSTRICTRC_VAL(rc)));
3156#endif
3157 }
3158 else
3159 {
3160 if (idxRegDsc >= 0)
3161 STAM_COUNTER_INC(&pThis->aStatRegReadsToR3[idxRegDsc]);
3162 }
3163 return rc;
3164}
3165
3166
3167DECLINLINE(VBOXSTRICTRC) hdaWriteReg(PPDMDEVINS pDevIns, PHDASTATE pThis, int idxRegDsc, uint32_t u32Value, char const *pszLog)
3168{
3169 if ( (HDA_REG(pThis, GCTL) & HDA_GCTL_CRST)
3170 || idxRegDsc == HDA_REG_GCTL)
3171 { /* likely */ }
3172 else
3173 {
3174 Log(("hdaWriteReg: Warning: Access to %s is blocked while controller is in reset mode\n", g_aHdaRegMap[idxRegDsc].pszName));
3175#if defined(IN_RING3) || defined(LOG_ENABLED)
3176 LogRel2(("HDA: Warning: Access to register %s is blocked while controller is in reset mode\n",
3177 g_aHdaRegMap[idxRegDsc].pszName));
3178#endif
3179 STAM_COUNTER_INC(&pThis->StatRegWritesBlockedByReset);
3180 return VINF_SUCCESS;
3181 }
3182
3183 /*
3184 * Handle RD (register description) flags.
3185 */
3186
3187 /* For SDI / SDO: Check if writes to those registers are allowed while SDCTL's RUN bit is set. */
3188 if (idxRegDsc >= HDA_NUM_GENERAL_REGS)
3189 {
3190 /*
3191 * Some OSes (like Win 10 AU) violate the spec by writing stuff to registers which are not supposed to be be touched
3192 * while SDCTL's RUN bit is set. So just ignore those values.
3193 */
3194 const uint32_t uSDCTL = HDA_STREAM_REG(pThis, CTL, HDA_SD_NUM_FROM_REG(pThis, CTL, idxRegDsc));
3195 if ( !(uSDCTL & HDA_SDCTL_RUN)
3196 || (g_aHdaRegMap[idxRegDsc].fFlags & HDA_RD_F_SD_WRITE_RUN))
3197 { /* likely */ }
3198 else
3199 {
3200 Log(("hdaWriteReg: Warning: Access to %s is blocked! %R[sdctl]\n", g_aHdaRegMap[idxRegDsc].pszName, uSDCTL));
3201#if defined(IN_RING3) || defined(LOG_ENABLED)
3202 LogRel2(("HDA: Warning: Access to register %s is blocked while the stream's RUN bit is set\n",
3203 g_aHdaRegMap[idxRegDsc].pszName));
3204#endif
3205 STAM_COUNTER_INC(&pThis->StatRegWritesBlockedByRun);
3206 return VINF_SUCCESS;
3207 }
3208 }
3209
3210#ifdef LOG_ENABLED
3211 uint32_t const idxRegMem = g_aHdaRegMap[idxRegDsc].idxReg;
3212 uint32_t const u32OldValue = pThis->au32Regs[idxRegMem];
3213#endif
3214 VBOXSTRICTRC rc = g_aHdaRegMap[idxRegDsc].pfnWrite(pDevIns, pThis, idxRegDsc, u32Value);
3215 Log3Func(("Written value %#x to %s[%d byte]; %x => %x%s, rc=%d\n", u32Value, g_aHdaRegMap[idxRegDsc].pszName,
3216 g_aHdaRegMap[idxRegDsc].cb, u32OldValue, pThis->au32Regs[idxRegMem], pszLog, VBOXSTRICTRC_VAL(rc)));
3217#ifndef IN_RING3
3218 if (rc == VINF_IOM_R3_MMIO_WRITE)
3219 STAM_COUNTER_INC(&pThis->aStatRegWritesToR3[idxRegDsc]);
3220 else
3221#endif
3222 STAM_COUNTER_INC(&pThis->aStatRegWrites[idxRegDsc]);
3223
3224 RT_NOREF(pszLog);
3225 return rc;
3226}
3227
3228
3229/**
3230 * @callback_method_impl{FNIOMMMIONEWWRITE,
3231 * Looks up and calls the appropriate handler.}
3232 */
3233static DECLCALLBACK(VBOXSTRICTRC) hdaMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
3234{
3235 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3236 RT_NOREF_PV(pvUser);
3237 Assert(pThis->uAlignmentCheckMagic == HDASTATE_ALIGNMENT_CHECK_MAGIC);
3238
3239 /*
3240 * Look up and log the access.
3241 */
3242 int idxRegDsc = hdaRegLookup(off);
3243#if defined(IN_RING3) || defined(LOG_ENABLED)
3244 uint32_t idxRegMem = idxRegDsc != -1 ? g_aHdaRegMap[idxRegDsc].idxReg : UINT32_MAX;
3245#endif
3246 uint64_t u64Value;
3247 if (cb == 4) u64Value = *(uint32_t const *)pv;
3248 else if (cb == 2) u64Value = *(uint16_t const *)pv;
3249 else if (cb == 1) u64Value = *(uint8_t const *)pv;
3250 else if (cb == 8) u64Value = *(uint64_t const *)pv;
3251 else
3252 ASSERT_GUEST_MSG_FAILED_RETURN(("cb=%u %.*Rhxs\n", cb, cb, pv),
3253 PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "odd write size: off=%RGp cb=%u\n", off, cb));
3254
3255 /*
3256 * The behavior of accesses that aren't aligned on natural boundraries is
3257 * undefined. Just reject them outright.
3258 */
3259 ASSERT_GUEST_MSG_RETURN((off & (cb - 1)) == 0, ("off=%RGp cb=%u %.*Rhxs\n", off, cb, cb, pv),
3260 PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "misaligned write access: off=%RGp cb=%u\n", off, cb));
3261
3262#ifdef LOG_ENABLED
3263 uint32_t const u32LogOldValue = idxRegDsc >= 0 ? pThis->au32Regs[idxRegMem] : UINT32_MAX;
3264# ifdef HDA_DEBUG_GUEST_RIP
3265 if (LogIs6Enabled())
3266 {
3267 PVMCPU pVCpu = (PVMCPU)PDMDevHlpGetVMCPU(pDevIns);
3268 Log6Func(("cs:rip=%04x:%016RX64 rflags=%08RX32\n", CPUMGetGuestCS(pVCpu), CPUMGetGuestRIP(pVCpu), CPUMGetGuestEFlags(pVCpu)));
3269 }
3270# endif
3271#endif
3272
3273 /*
3274 * Try for a direct hit first.
3275 */
3276 VBOXSTRICTRC rc;
3277 if (idxRegDsc >= 0 && g_aHdaRegMap[idxRegDsc].cb == cb)
3278 {
3279 DEVHDA_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
3280
3281 Log3Func(("@%#05x u%u=%#0*RX64 %s\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, g_aHdaRegMap[idxRegDsc].pszName));
3282 rc = hdaWriteReg(pDevIns, pThis, idxRegDsc, u64Value, "");
3283 Log3Func((" %#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
3284
3285 DEVHDA_UNLOCK(pDevIns, pThis);
3286 }
3287 /*
3288 * Sub-register access. Supply missing bits as needed.
3289 */
3290 else if ( idxRegDsc >= 0
3291 && cb < g_aHdaRegMap[idxRegDsc].cb)
3292 {
3293 DEVHDA_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
3294
3295 u64Value |= pThis->au32Regs[g_aHdaRegMap[idxRegDsc].idxReg]
3296 & g_afMasks[g_aHdaRegMap[idxRegDsc].cb]
3297 & ~g_afMasks[cb];
3298 Log4Func(("@%#05x u%u=%#0*RX64 cb=%#x cbReg=%x %s\n"
3299 "hdaMmioWrite: Supplying missing bits (%#x): %#llx -> %#llx ...\n",
3300 (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, cb, g_aHdaRegMap[idxRegDsc].cb, g_aHdaRegMap[idxRegDsc].pszName,
3301 g_afMasks[g_aHdaRegMap[idxRegDsc].cb] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
3302 rc = hdaWriteReg(pDevIns, pThis, idxRegDsc, u64Value, "");
3303 Log4Func((" %#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
3304 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegSubWrite));
3305
3306 DEVHDA_UNLOCK(pDevIns, pThis);
3307 }
3308 /*
3309 * Partial or multiple register access, loop thru the requested memory.
3310 */
3311 else
3312 {
3313#ifdef IN_RING3
3314 DEVHDA_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
3315
3316 if (idxRegDsc == -1)
3317 Log4Func(("@%#05x u32=%#010x cb=%d\n", (uint32_t)off, *(uint32_t const *)pv, cb));
3318 else if (g_aHdaRegMap[idxRegDsc].cb == cb)
3319 Log4Func(("@%#05x u%u=%#0*RX64 %s\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, g_aHdaRegMap[idxRegDsc].pszName));
3320 else
3321 Log4Func(("@%#05x u%u=%#0*RX64 %s - mismatch cbReg=%u\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value,
3322 g_aHdaRegMap[idxRegDsc].pszName, g_aHdaRegMap[idxRegDsc].cb));
3323
3324 /*
3325 * If it's an access beyond the start of the register, shift the input
3326 * value and fill in missing bits. Natural alignment rules means we
3327 * will only see 1 or 2 byte accesses of this kind, so no risk of
3328 * shifting out input values.
3329 */
3330 if (idxRegDsc < 0)
3331 {
3332 idxRegDsc = hdaR3RegLookupWithin(off);
3333 if (idxRegDsc != -1)
3334 {
3335 uint32_t const cbBefore = (uint32_t)off - g_aHdaRegMap[idxRegDsc].off;
3336 Assert(cbBefore > 0 && cbBefore < 4);
3337 off -= cbBefore;
3338 idxRegMem = g_aHdaRegMap[idxRegDsc].idxReg;
3339 u64Value <<= cbBefore * 8;
3340 u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbBefore];
3341 Log4Func((" Within register, supplied %u leading bits: %#llx -> %#llx ...\n",
3342 cbBefore * 8, ~(uint64_t)g_afMasks[cbBefore] & u64Value, u64Value));
3343 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegMultiWrites));
3344 }
3345 else
3346 STAM_COUNTER_INC(&pThis->StatRegUnknownWrites);
3347 }
3348 else
3349 {
3350 Log4(("hdaMmioWrite: multi write: %s\n", g_aHdaRegMap[idxRegDsc].pszName));
3351 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegMultiWrites));
3352 }
3353
3354 /* Loop thru the write area, it may cover multiple registers. */
3355 rc = VINF_SUCCESS;
3356 for (;;)
3357 {
3358 uint32_t cbReg;
3359 if (idxRegDsc >= 0)
3360 {
3361 idxRegMem = g_aHdaRegMap[idxRegDsc].idxReg;
3362 cbReg = g_aHdaRegMap[idxRegDsc].cb;
3363 if (cb < cbReg)
3364 {
3365 u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbReg] & ~g_afMasks[cb];
3366 Log4Func((" Supplying missing bits (%#x): %#llx -> %#llx ...\n",
3367 g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
3368 }
3369# ifdef LOG_ENABLED
3370 uint32_t uLogOldVal = pThis->au32Regs[idxRegMem];
3371# endif
3372 rc = hdaWriteReg(pDevIns, pThis, idxRegDsc, u64Value & g_afMasks[cbReg], "*");
3373 Log4Func((" %#x -> %#x\n", uLogOldVal, pThis->au32Regs[idxRegMem]));
3374 }
3375 else
3376 {
3377 LogRel(("HDA: Invalid write access @0x%x\n", (uint32_t)off));
3378 cbReg = 1;
3379 }
3380 if (rc != VINF_SUCCESS)
3381 break;
3382 if (cbReg >= cb)
3383 break;
3384
3385 /* Advance. */
3386 off += cbReg;
3387 cb -= cbReg;
3388 u64Value >>= cbReg * 8;
3389 if (idxRegDsc == -1)
3390 idxRegDsc = hdaRegLookup(off);
3391 else
3392 {
3393 idxRegDsc++;
3394 if ( (unsigned)idxRegDsc >= RT_ELEMENTS(g_aHdaRegMap)
3395 || g_aHdaRegMap[idxRegDsc].off != off)
3396 idxRegDsc = -1;
3397 }
3398 }
3399
3400 DEVHDA_UNLOCK(pDevIns, pThis);
3401
3402#else /* !IN_RING3 */
3403 /* Take the simple way out. */
3404 rc = VINF_IOM_R3_MMIO_WRITE;
3405#endif /* !IN_RING3 */
3406 }
3407
3408 return rc;
3409}
3410
3411#ifdef IN_RING3
3412
3413
3414/*********************************************************************************************************************************
3415* Saved state *
3416*********************************************************************************************************************************/
3417
3418/**
3419 * @callback_method_impl{FNSSMFIELDGETPUT,
3420 * Version 6 saves the IOC flag in HDABDLEDESC::fFlags as a bool}
3421 */
3422static DECLCALLBACK(int)
3423hdaR3GetPutTrans_HDABDLEDESC_fFlags_6(PSSMHANDLE pSSM, const struct SSMFIELD *pField, void *pvStruct,
3424 uint32_t fFlags, bool fGetOrPut, void *pvUser)
3425{
3426 PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
3427 RT_NOREF(pSSM, pField, pvStruct, fFlags);
3428 AssertReturn(fGetOrPut, VERR_INTERNAL_ERROR_4);
3429 bool fIoc;
3430 int rc = pDevIns->pHlpR3->pfnSSMGetBool(pSSM, &fIoc);
3431 if (RT_SUCCESS(rc))
3432 {
3433 PHDABDLEDESC pDesc = (PHDABDLEDESC)pvStruct;
3434 pDesc->fFlags = fIoc ? HDA_BDLE_F_IOC : 0;
3435 }
3436 return rc;
3437}
3438
3439
3440/**
3441 * @callback_method_impl{FNSSMFIELDGETPUT,
3442 * Versions 1 thru 4 save the IOC flag in HDASTREAMSTATE::DescfFlags as a bool}
3443 */
3444static DECLCALLBACK(int)
3445hdaR3GetPutTrans_HDABDLE_Desc_fFlags_1thru4(PSSMHANDLE pSSM, const struct SSMFIELD *pField, void *pvStruct,
3446 uint32_t fFlags, bool fGetOrPut, void *pvUser)
3447{
3448 PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
3449 RT_NOREF(pSSM, pField, pvStruct, fFlags);
3450 AssertReturn(fGetOrPut, VERR_INTERNAL_ERROR_4);
3451 bool fIoc;
3452 int rc = pDevIns->pHlpR3->pfnSSMGetBool(pSSM, &fIoc);
3453 if (RT_SUCCESS(rc))
3454 {
3455 HDABDLELEGACY *pState = (HDABDLELEGACY *)pvStruct;
3456 pState->Desc.fFlags = fIoc ? HDA_BDLE_F_IOC : 0;
3457 }
3458 return rc;
3459}
3460
3461
3462static int hdaR3SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)
3463{
3464 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3465# ifdef LOG_ENABLED
3466 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3467# endif
3468
3469 Log2Func(("[SD%RU8]\n", pStreamShared->u8SD));
3470
3471 /* Save stream ID. */
3472 Assert(pStreamShared->u8SD < HDA_MAX_STREAMS);
3473 int rc = pHlp->pfnSSMPutU8(pSSM, pStreamShared->u8SD);
3474 AssertRCReturn(rc, rc);
3475
3476 rc = pHlp->pfnSSMPutStructEx(pSSM, &pStreamShared->State, sizeof(pStreamShared->State),
3477 0 /*fFlags*/, g_aSSMStreamStateFields7, NULL);
3478 AssertRCReturn(rc, rc);
3479
3480 AssertCompile(sizeof(pStreamShared->State.idxCurBdle) == sizeof(uint8_t) && RT_ELEMENTS(pStreamShared->State.aBdl) == 256);
3481 HDABDLEDESC TmpDesc = *(HDABDLEDESC *)&pStreamShared->State.aBdl[pStreamShared->State.idxCurBdle];
3482 rc = pHlp->pfnSSMPutStructEx(pSSM, &TmpDesc, sizeof(TmpDesc), 0 /*fFlags*/, g_aSSMBDLEDescFields7, NULL);
3483 AssertRCReturn(rc, rc);
3484
3485 HDABDLESTATELEGACY TmpState = { pStreamShared->State.idxCurBdle, 0, pStreamShared->State.offCurBdle, 0 };
3486 rc = pHlp->pfnSSMPutStructEx(pSSM, &TmpState, sizeof(TmpState), 0 /*fFlags*/, g_aSSMBDLEStateFields7, NULL);
3487 AssertRCReturn(rc, rc);
3488
3489 PAUDMIXSINK pSink = NULL;
3490 uint32_t cbCircBuf = 0;
3491 uint32_t cbCircBufUsed = 0;
3492 if (pStreamR3->State.pCircBuf)
3493 {
3494 cbCircBuf = (uint32_t)RTCircBufSize(pStreamR3->State.pCircBuf);
3495
3496 /* We take the AIO lock here and releases it after saving the buffer,
3497 otherwise the AIO thread could race us reading out the buffer data. */
3498 pSink = pStreamR3->pMixSink ? pStreamR3->pMixSink->pMixSink : NULL;
3499 if ( !pSink
3500 || RT_SUCCESS(AudioMixerSinkTryLock(pSink)))
3501 {
3502 cbCircBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
3503 if (cbCircBufUsed == 0 && pSink)
3504 AudioMixerSinkUnlock(pSink);
3505 }
3506 }
3507
3508 pHlp->pfnSSMPutU32(pSSM, cbCircBuf);
3509 rc = pHlp->pfnSSMPutU32(pSSM, cbCircBufUsed);
3510
3511 if (cbCircBufUsed > 0)
3512 {
3513 /* HACK ALERT! We cannot remove data from the buffer (live snapshot),
3514 we use RTCircBufOffsetRead and RTCircBufAcquireReadBlock
3515 creatively to get at the other buffer segment in case
3516 of a wraparound. */
3517 size_t const offBuf = RTCircBufOffsetRead(pStreamR3->State.pCircBuf);
3518 void *pvBuf = NULL;
3519 size_t cbBuf = 0;
3520 RTCircBufAcquireReadBlock(pStreamR3->State.pCircBuf, cbCircBufUsed, &pvBuf, &cbBuf);
3521 Assert(cbBuf);
3522 rc = pHlp->pfnSSMPutMem(pSSM, pvBuf, cbBuf);
3523 if (cbBuf < cbCircBufUsed)
3524 rc = pHlp->pfnSSMPutMem(pSSM, (uint8_t *)pvBuf - offBuf, cbCircBufUsed - cbBuf);
3525 RTCircBufReleaseReadBlock(pStreamR3->State.pCircBuf, 0 /* Don't advance read pointer! */);
3526
3527 if (pSink)
3528 AudioMixerSinkUnlock(pSink);
3529 }
3530
3531 Log2Func(("[SD%RU8] LPIB=%RU32, CBL=%RU32, LVI=%RU32\n", pStreamR3->u8SD, HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD),
3532 HDA_STREAM_REG(pThis, CBL, pStreamShared->u8SD), HDA_STREAM_REG(pThis, LVI, pStreamShared->u8SD)));
3533
3534#ifdef LOG_ENABLED
3535 hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
3536#endif
3537
3538 return rc;
3539}
3540
3541/**
3542 * @callback_method_impl{FNSSMDEVSAVEEXEC}
3543 */
3544static DECLCALLBACK(int) hdaR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
3545{
3546 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3547 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
3548 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3549
3550 /* Save Codec nodes states. */
3551 hdaCodecSaveState(pDevIns, &pThisCC->Codec, pSSM);
3552
3553 /* Save MMIO registers. */
3554 pHlp->pfnSSMPutU32(pSSM, RT_ELEMENTS(pThis->au32Regs));
3555 pHlp->pfnSSMPutMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
3556
3557 /* Save controller-specifc internals. */
3558 pHlp->pfnSSMPutU64(pSSM, pThis->tsWalClkStart);
3559 pHlp->pfnSSMPutU8(pSSM, pThis->u8IRQL);
3560
3561 /* Save number of streams. */
3562 pHlp->pfnSSMPutU32(pSSM, HDA_MAX_STREAMS);
3563
3564 /* Save stream states. */
3565 for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
3566 {
3567 int rc = hdaR3SaveStream(pDevIns, pSSM, &pThis->aStreams[i], &pThisCC->aStreams[i]);
3568 AssertRCReturn(rc, rc);
3569 }
3570
3571 return VINF_SUCCESS;
3572}
3573
3574/**
3575 * @callback_method_impl{FNSSMDEVLOADDONE,
3576 * Finishes stream setup and resuming.}
3577 */
3578static DECLCALLBACK(int) hdaR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
3579{
3580 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3581 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
3582 LogFlowFuncEnter();
3583
3584 /*
3585 * Enable all previously active streams.
3586 */
3587 for (size_t i = 0; i < HDA_MAX_STREAMS; i++)
3588 {
3589 PHDASTREAM pStreamShared = &pThis->aStreams[i];
3590
3591 bool fActive = RT_BOOL(HDA_STREAM_REG(pThis, CTL, i) & HDA_SDCTL_RUN);
3592 if (fActive)
3593 {
3594 PHDASTREAMR3 pStreamR3 = &pThisCC->aStreams[i];
3595
3596 /* (Re-)enable the stream. */
3597 int rc2 = hdaR3StreamEnable(pThis, pStreamShared, pStreamR3, true /* fEnable */);
3598 AssertRC(rc2);
3599
3600 /* Add the stream to the device setup. */
3601 rc2 = hdaR3AddStream(pThisCC, &pStreamShared->State.Cfg);
3602 AssertRC(rc2);
3603
3604 /* Use the LPIB to find the current scheduling position. If this isn't
3605 exactly on a scheduling item adjust LPIB down to the start of the
3606 current. This isn't entirely ideal, but it avoid the IRQ counting
3607 issue if we round it upwards. (it is also a lot simpler) */
3608 uint32_t uLpib = HDA_STREAM_REG(pThis, LPIB, i);
3609 AssertLogRelMsgStmt(uLpib < pStreamShared->u32CBL, ("LPIB=%#RX32 CBL=%#RX32\n", uLpib, pStreamShared->u32CBL),
3610 HDA_STREAM_REG(pThis, LPIB, i) = uLpib = 0);
3611
3612 uint32_t off = 0;
3613 for (uint32_t j = 0; j < pStreamShared->State.cSchedule; j++)
3614 {
3615 AssertReturn(pStreamShared->State.aSchedule[j].cbPeriod >= 1 && pStreamShared->State.aSchedule[j].cLoops >= 1,
3616 pDevIns->pHlpR3->pfnSSMSetLoadError(pSSM, VERR_INTERNAL_ERROR_2, RT_SRC_POS,
3617 "Stream #%u, sched #%u: cbPeriod=%u cLoops=%u\n",
3618 pStreamShared->u8SD, j,
3619 pStreamShared->State.aSchedule[j].cbPeriod,
3620 pStreamShared->State.aSchedule[j].cLoops));
3621 uint32_t cbCur = pStreamShared->State.aSchedule[j].cbPeriod
3622 * pStreamShared->State.aSchedule[j].cLoops;
3623 if (uLpib >= off + cbCur)
3624 off += cbCur;
3625 else
3626 {
3627 uint32_t const offDelta = uLpib - off;
3628 uint32_t idxLoop = offDelta / pStreamShared->State.aSchedule[j].cbPeriod;
3629 uint32_t offLoop = offDelta % pStreamShared->State.aSchedule[j].cbPeriod;
3630 if (offLoop)
3631 {
3632 /** @todo somehow bake this into the DMA timer logic. */
3633 LogFunc(("stream #%u: LPIB=%#RX32; adjusting due to scheduling clash: -%#x (j=%u idxLoop=%u cbPeriod=%#x)\n",
3634 pStreamShared->u8SD, uLpib, offLoop, j, idxLoop, pStreamShared->State.aSchedule[j].cbPeriod));
3635 uLpib -= offLoop;
3636 HDA_STREAM_REG(pThis, LPIB, i) = uLpib;
3637 }
3638 pStreamShared->State.idxSchedule = (uint16_t)j;
3639 pStreamShared->State.idxScheduleLoop = (uint16_t)idxLoop;
3640 off = UINT32_MAX;
3641 break;
3642 }
3643 }
3644 Assert(off == UINT32_MAX);
3645
3646 /* Now figure out the current BDLE and the offset within it. */
3647 off = 0;
3648 for (uint32_t j = 0; j < pStreamShared->State.cBdles; j++)
3649 if (uLpib >= off + pStreamShared->State.aBdl[j].cb)
3650 off += pStreamShared->State.aBdl[j].cb;
3651 else
3652 {
3653 pStreamShared->State.idxCurBdle = j;
3654 pStreamShared->State.offCurBdle = uLpib - off;
3655 off = UINT32_MAX;
3656 break;
3657 }
3658 AssertReturn(off == UINT32_MAX, pDevIns->pHlpR3->pfnSSMSetLoadError(pSSM, VERR_INTERNAL_ERROR_3, RT_SRC_POS,
3659 "Stream #%u: LPIB=%#RX32 not found in loaded BDL\n",
3660 pStreamShared->u8SD, uLpib));
3661
3662 /* Avoid going through the timer here by calling the stream's timer function directly.
3663 * Should speed up starting the stream transfers. */
3664 PDMDevHlpTimerLockClock2(pDevIns, pStreamShared->hTimer, &pThis->CritSect, VERR_IGNORED);
3665 uint64_t tsNow = hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
3666 PDMDevHlpTimerUnlockClock2(pDevIns, pStreamShared->hTimer, &pThis->CritSect);
3667
3668 hdaR3StreamMarkStarted(pDevIns, pThis, pStreamShared, tsNow);
3669 }
3670 }
3671
3672 LogFlowFuncLeave();
3673 return VINF_SUCCESS;
3674}
3675
3676/**
3677 * Handles loading of all saved state versions older than the current one.
3678 *
3679 * @param pDevIns The device instance.
3680 * @param pThis Pointer to the shared HDA state.
3681 * @param pThisCC Pointer to the ring-3 HDA state.
3682 * @param pSSM The saved state handle.
3683 * @param uVersion Saved state version to load.
3684 */
3685static int hdaR3LoadExecLegacy(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PSSMHANDLE pSSM, uint32_t uVersion)
3686{
3687 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3688 int rc;
3689
3690 /*
3691 * Load MMIO registers.
3692 */
3693 uint32_t cRegs;
3694 switch (uVersion)
3695 {
3696 case HDA_SAVED_STATE_VERSION_1:
3697 /* Starting with r71199, we would save 112 instead of 113
3698 registers due to some code cleanups. This only affected trunk
3699 builds in the 4.1 development period. */
3700 cRegs = 113;
3701 if (pHlp->pfnSSMHandleRevision(pSSM) >= 71199)
3702 {
3703 uint32_t uVer = pHlp->pfnSSMHandleVersion(pSSM);
3704 if ( VBOX_FULL_VERSION_GET_MAJOR(uVer) == 4
3705 && VBOX_FULL_VERSION_GET_MINOR(uVer) == 0
3706 && VBOX_FULL_VERSION_GET_BUILD(uVer) >= 51)
3707 cRegs = 112;
3708 }
3709 break;
3710
3711 case HDA_SAVED_STATE_VERSION_2:
3712 case HDA_SAVED_STATE_VERSION_3:
3713 cRegs = 112;
3714 AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= 112);
3715 break;
3716
3717 /* Since version 4 we store the register count to stay flexible. */
3718 case HDA_SAVED_STATE_VERSION_4:
3719 case HDA_SAVED_STATE_VERSION_5:
3720 case HDA_SAVED_STATE_VERSION_6:
3721 rc = pHlp->pfnSSMGetU32(pSSM, &cRegs);
3722 AssertRCReturn(rc, rc);
3723 if (cRegs != RT_ELEMENTS(pThis->au32Regs))
3724 LogRel(("HDA: SSM version cRegs is %RU32, expected %RU32\n", cRegs, RT_ELEMENTS(pThis->au32Regs)));
3725 break;
3726
3727 default:
3728 AssertLogRelMsgFailedReturn(("HDA: Internal Error! Didn't expect saved state version %RU32 ending up in hdaR3LoadExecLegacy!\n",
3729 uVersion), VERR_INTERNAL_ERROR_5);
3730 }
3731
3732 if (cRegs >= RT_ELEMENTS(pThis->au32Regs))
3733 {
3734 pHlp->pfnSSMGetMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
3735 pHlp->pfnSSMSkip(pSSM, sizeof(uint32_t) * (cRegs - RT_ELEMENTS(pThis->au32Regs)));
3736 }
3737 else
3738 pHlp->pfnSSMGetMem(pSSM, pThis->au32Regs, sizeof(uint32_t) * cRegs);
3739
3740 /* Make sure to update the base addresses first before initializing any streams down below. */
3741 pThis->u64CORBBase = RT_MAKE_U64(HDA_REG(pThis, CORBLBASE), HDA_REG(pThis, CORBUBASE));
3742 pThis->u64RIRBBase = RT_MAKE_U64(HDA_REG(pThis, RIRBLBASE), HDA_REG(pThis, RIRBUBASE));
3743 pThis->u64DPBase = RT_MAKE_U64(HDA_REG(pThis, DPLBASE) & DPBASE_ADDR_MASK, HDA_REG(pThis, DPUBASE));
3744
3745 /* Also make sure to update the DMA position bit if this was enabled when saving the state. */
3746 pThis->fDMAPosition = RT_BOOL(HDA_REG(pThis, DPLBASE) & RT_BIT_32(0));
3747
3748 /*
3749 * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
3750 *
3751 * Note: Saved states < v5 store LVI (u32BdleMaxCvi) for
3752 * *every* BDLE state, whereas it only needs to be stored
3753 * *once* for every stream. Most of the BDLE state we can
3754 * get out of the registers anyway, so just ignore those values.
3755 *
3756 * Also, only the current BDLE was saved, regardless whether
3757 * there were more than one (and there are at least two entries,
3758 * according to the spec).
3759 */
3760 switch (uVersion)
3761 {
3762 case HDA_SAVED_STATE_VERSION_1:
3763 case HDA_SAVED_STATE_VERSION_2:
3764 case HDA_SAVED_STATE_VERSION_3:
3765 case HDA_SAVED_STATE_VERSION_4:
3766 {
3767 /* Only load the internal states.
3768 * The rest will be initialized from the saved registers later. */
3769
3770 /* Note 1: Only the *current* BDLE for a stream was saved! */
3771 /* Note 2: The stream's saving order is/was fixed, so don't touch! */
3772
3773 HDABDLELEGACY BDLE;
3774
3775 /* Output */
3776 PHDASTREAM pStreamShared = &pThis->aStreams[4];
3777 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, &pThisCC->aStreams[4], 4 /* Stream descriptor, hardcoded */);
3778 AssertRCReturn(rc, rc);
3779 RT_ZERO(BDLE);
3780 rc = pHlp->pfnSSMGetStructEx(pSSM, &BDLE, sizeof(BDLE), 0 /* fFlags */, g_aSSMStreamBdleFields1234, pDevIns);
3781 AssertRCReturn(rc, rc);
3782 pStreamShared->State.idxCurBdle = (uint8_t)BDLE.State.u32BDLIndex; /* not necessary */
3783
3784 /* Microphone-In */
3785 pStreamShared = &pThis->aStreams[2];
3786 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, &pThisCC->aStreams[2], 2 /* Stream descriptor, hardcoded */);
3787 AssertRCReturn(rc, rc);
3788 rc = pHlp->pfnSSMGetStructEx(pSSM, &BDLE, sizeof(BDLE), 0 /* fFlags */, g_aSSMStreamBdleFields1234, pDevIns);
3789 AssertRCReturn(rc, rc);
3790 pStreamShared->State.idxCurBdle = (uint8_t)BDLE.State.u32BDLIndex; /* not necessary */
3791
3792 /* Line-In */
3793 pStreamShared = &pThis->aStreams[0];
3794 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, &pThisCC->aStreams[0], 0 /* Stream descriptor, hardcoded */);
3795 AssertRCReturn(rc, rc);
3796 rc = pHlp->pfnSSMGetStructEx(pSSM, &BDLE, sizeof(BDLE), 0 /* fFlags */, g_aSSMStreamBdleFields1234, pDevIns);
3797 AssertRCReturn(rc, rc);
3798 pStreamShared->State.idxCurBdle = (uint8_t)BDLE.State.u32BDLIndex; /* not necessary */
3799 break;
3800 }
3801
3802 /*
3803 * v5 & v6 - Since v5 we support flexible stream and BDLE counts.
3804 */
3805 default:
3806 {
3807 /* Stream count. */
3808 uint32_t cStreams;
3809 rc = pHlp->pfnSSMGetU32(pSSM, &cStreams);
3810 AssertRCReturn(rc, rc);
3811 if (cStreams > HDA_MAX_STREAMS)
3812 return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
3813 N_("State contains %u streams while %u is the maximum supported"),
3814 cStreams, HDA_MAX_STREAMS);
3815
3816 /* Load stream states. */
3817 for (uint32_t i = 0; i < cStreams; i++)
3818 {
3819 uint8_t idStream;
3820 rc = pHlp->pfnSSMGetU8(pSSM, &idStream);
3821 AssertRCReturn(rc, rc);
3822
3823 HDASTREAM StreamDummyShared;
3824 HDASTREAMR3 StreamDummyR3;
3825 PHDASTREAM pStreamShared = idStream < RT_ELEMENTS(pThis->aStreams) ? &pThis->aStreams[idStream] : &StreamDummyShared;
3826 PHDASTREAMR3 pStreamR3 = idStream < RT_ELEMENTS(pThisCC->aStreams) ? &pThisCC->aStreams[idStream] : &StreamDummyR3;
3827 AssertLogRelMsgStmt(idStream < RT_ELEMENTS(pThisCC->aStreams),
3828 ("HDA stream ID=%RU8 not supported, skipping loadingit ...\n", idStream),
3829 RT_ZERO(StreamDummyShared); RT_ZERO(StreamDummyR3));
3830
3831 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, pStreamR3, idStream);
3832 if (RT_FAILURE(rc))
3833 {
3834 LogRel(("HDA: Stream #%RU32: Setting up of stream %RU8 failed, rc=%Rrc\n", i, idStream, rc));
3835 break;
3836 }
3837
3838 /*
3839 * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
3840 */
3841 if (uVersion == HDA_SAVED_STATE_VERSION_5)
3842 {
3843 struct V5HDASTREAMSTATE /* HDASTREAMSTATE + HDABDLE */
3844 {
3845 uint16_t cBLDEs;
3846 uint16_t uCurBDLE;
3847 uint32_t u32BDLEIndex;
3848 uint32_t cbBelowFIFOW;
3849 uint32_t u32BufOff;
3850 } Tmp;
3851 static SSMFIELD const g_aV5State1Fields[] =
3852 {
3853 SSMFIELD_ENTRY(V5HDASTREAMSTATE, cBLDEs),
3854 SSMFIELD_ENTRY(V5HDASTREAMSTATE, uCurBDLE),
3855 SSMFIELD_ENTRY_TERM()
3856 };
3857 rc = pHlp->pfnSSMGetStructEx(pSSM, &Tmp, sizeof(Tmp), 0 /* fFlags */, g_aV5State1Fields, NULL);
3858 AssertRCReturn(rc, rc);
3859 pStreamShared->State.idxCurBdle = (uint8_t)Tmp.uCurBDLE; /* not necessary */
3860
3861 for (uint16_t a = 0; a < Tmp.cBLDEs; a++)
3862 {
3863 static SSMFIELD const g_aV5State2Fields[] =
3864 {
3865 SSMFIELD_ENTRY(V5HDASTREAMSTATE, u32BDLEIndex),
3866 SSMFIELD_ENTRY_OLD(au8FIFO, 256),
3867 SSMFIELD_ENTRY(V5HDASTREAMSTATE, cbBelowFIFOW),
3868 SSMFIELD_ENTRY_TERM()
3869 };
3870 rc = pHlp->pfnSSMGetStructEx(pSSM, &Tmp, sizeof(Tmp), 0 /* fFlags */, g_aV5State2Fields, NULL);
3871 AssertRCReturn(rc, rc);
3872 }
3873 }
3874 else
3875 {
3876 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State, sizeof(HDASTREAMSTATE),
3877 0 /* fFlags */, g_aSSMStreamStateFields6, NULL);
3878 AssertRCReturn(rc, rc);
3879
3880 HDABDLEDESC IgnDesc;
3881 rc = pHlp->pfnSSMGetStructEx(pSSM, &IgnDesc, sizeof(IgnDesc), 0 /* fFlags */, g_aSSMBDLEDescFields6, pDevIns);
3882 AssertRCReturn(rc, rc);
3883
3884 HDABDLESTATELEGACY IgnState;
3885 rc = pHlp->pfnSSMGetStructEx(pSSM, &IgnState, sizeof(IgnState), 0 /* fFlags */, g_aSSMBDLEStateFields6, NULL);
3886 AssertRCReturn(rc, rc);
3887
3888 Log2Func(("[SD%RU8] LPIB=%RU32, CBL=%RU32, LVI=%RU32\n", idStream, HDA_STREAM_REG(pThis, LPIB, idStream),
3889 HDA_STREAM_REG(pThis, CBL, idStream), HDA_STREAM_REG(pThis, LVI, idStream)));
3890#ifdef LOG_ENABLED
3891 hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
3892#endif
3893 }
3894
3895 } /* for cStreams */
3896 break;
3897 } /* default */
3898 }
3899
3900 return rc;
3901}
3902
3903/**
3904 * @callback_method_impl{FNSSMDEVLOADEXEC}
3905 */
3906static DECLCALLBACK(int) hdaR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
3907{
3908 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3909 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
3910 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3911
3912 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
3913
3914 LogRel2(("hdaR3LoadExec: uVersion=%RU32, uPass=0x%x\n", uVersion, uPass));
3915
3916 /*
3917 * Load Codec nodes states.
3918 */
3919 int rc = hdaR3CodecLoadState(pDevIns, &pThisCC->Codec, pSSM, uVersion);
3920 if (RT_FAILURE(rc))
3921 {
3922 LogRel(("HDA: Failed loading codec state (version %RU32, pass 0x%x), rc=%Rrc\n", uVersion, uPass, rc));
3923 return rc;
3924 }
3925
3926 if (uVersion <= HDA_SAVED_STATE_VERSION_6) /* Handle older saved states? */
3927 return hdaR3LoadExecLegacy(pDevIns, pThis, pThisCC, pSSM, uVersion);
3928
3929 /*
3930 * Load MMIO registers.
3931 */
3932 uint32_t cRegs;
3933 rc = pHlp->pfnSSMGetU32(pSSM, &cRegs); AssertRCReturn(rc, rc);
3934 AssertRCReturn(rc, rc);
3935 if (cRegs != RT_ELEMENTS(pThis->au32Regs))
3936 LogRel(("HDA: SSM version cRegs is %RU32, expected %RU32\n", cRegs, RT_ELEMENTS(pThis->au32Regs)));
3937
3938 if (cRegs >= RT_ELEMENTS(pThis->au32Regs))
3939 {
3940 pHlp->pfnSSMGetMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
3941 rc = pHlp->pfnSSMSkip(pSSM, sizeof(uint32_t) * (cRegs - RT_ELEMENTS(pThis->au32Regs)));
3942 AssertRCReturn(rc, rc);
3943 }
3944 else
3945 {
3946 rc = pHlp->pfnSSMGetMem(pSSM, pThis->au32Regs, sizeof(uint32_t) * cRegs);
3947 AssertRCReturn(rc, rc);
3948 }
3949
3950 /* Make sure to update the base addresses first before initializing any streams down below. */
3951 pThis->u64CORBBase = RT_MAKE_U64(HDA_REG(pThis, CORBLBASE), HDA_REG(pThis, CORBUBASE));
3952 pThis->u64RIRBBase = RT_MAKE_U64(HDA_REG(pThis, RIRBLBASE), HDA_REG(pThis, RIRBUBASE));
3953 pThis->u64DPBase = RT_MAKE_U64(HDA_REG(pThis, DPLBASE) & DPBASE_ADDR_MASK, HDA_REG(pThis, DPUBASE));
3954
3955 /* Also make sure to update the DMA position bit if this was enabled when saving the state. */
3956 pThis->fDMAPosition = RT_BOOL(HDA_REG(pThis, DPLBASE) & RT_BIT_32(0));
3957
3958 /*
3959 * Load controller-specific internals.
3960 */
3961 if ( uVersion >= HDA_SAVED_STATE_WITHOUT_PERIOD
3962 /* Don't annoy other team mates (forgot this for state v7): */
3963 || pHlp->pfnSSMHandleRevision(pSSM) >= 116273
3964 || pHlp->pfnSSMHandleVersion(pSSM) >= VBOX_FULL_VERSION_MAKE(5, 2, 0))
3965 {
3966 pHlp->pfnSSMGetU64(pSSM, &pThis->tsWalClkStart); /* Was current wall clock */
3967 rc = pHlp->pfnSSMGetU8(pSSM, &pThis->u8IRQL);
3968 AssertRCReturn(rc, rc);
3969
3970 /* Convert the saved wall clock timestamp to a start timestamp. */
3971 if (uVersion < HDA_SAVED_STATE_WITHOUT_PERIOD && pThis->tsWalClkStart != 0)
3972 {
3973 uint64_t const cTimerTicksPerSec = PDMDevHlpTimerGetFreq(pDevIns, pThis->aStreams[0].hTimer);
3974 AssertLogRel(cTimerTicksPerSec <= UINT32_MAX);
3975 pThis->tsWalClkStart = ASMMultU64ByU32DivByU32(pThis->tsWalClkStart,
3976 cTimerTicksPerSec,
3977 24000000 /* wall clock freq */);
3978 pThis->tsWalClkStart = PDMDevHlpTimerGet(pDevIns, pThis->aStreams[0].hTimer) - pThis->tsWalClkStart;
3979 }
3980 }
3981
3982 /*
3983 * Load streams.
3984 */
3985 uint32_t cStreams;
3986 rc = pHlp->pfnSSMGetU32(pSSM, &cStreams);
3987 AssertRCReturn(rc, rc);
3988 if (cStreams > HDA_MAX_STREAMS)
3989 return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
3990 N_("State contains %u streams while %u is the maximum supported"),
3991 cStreams, HDA_MAX_STREAMS);
3992 Log2Func(("cStreams=%RU32\n", cStreams));
3993
3994 /* Load stream states. */
3995 for (uint32_t i = 0; i < cStreams; i++)
3996 {
3997 uint8_t idStream;
3998 rc = pHlp->pfnSSMGetU8(pSSM, &idStream);
3999 AssertRCReturn(rc, rc);
4000
4001 /* Paranoia. */
4002 AssertLogRelMsgReturn(idStream < HDA_MAX_STREAMS,
4003 ("HDA: Saved state contains bogus stream ID %RU8 for stream #%RU8", idStream, i),
4004 VERR_SSM_INVALID_STATE);
4005
4006 HDASTREAM StreamDummyShared;
4007 HDASTREAMR3 StreamDummyR3;
4008 PHDASTREAM pStreamShared = idStream < RT_ELEMENTS(pThis->aStreams) ? &pThis->aStreams[idStream] : &StreamDummyShared;
4009 PHDASTREAMR3 pStreamR3 = idStream < RT_ELEMENTS(pThisCC->aStreams) ? &pThisCC->aStreams[idStream] : &StreamDummyR3;
4010 AssertLogRelMsgStmt(idStream < RT_ELEMENTS(pThisCC->aStreams),
4011 ("HDA stream ID=%RU8 not supported, skipping loadingit ...\n", idStream),
4012 RT_ZERO(StreamDummyShared); RT_ZERO(StreamDummyR3));
4013
4014 PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_IGNORED); /* timer code requires this */
4015 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, pStreamR3, idStream);
4016 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4017 if (RT_FAILURE(rc))
4018 {
4019 LogRel(("HDA: Stream #%RU8: Setting up failed, rc=%Rrc\n", idStream, rc));
4020 /* Continue. */
4021 }
4022
4023 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State, sizeof(HDASTREAMSTATE),
4024 0 /* fFlags */, g_aSSMStreamStateFields7, NULL);
4025 AssertRCReturn(rc, rc);
4026
4027 /*
4028 * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
4029 * Obsolete. Derived from LPID now.
4030 */
4031 HDABDLEDESC IgnDesc;
4032 rc = pHlp->pfnSSMGetStructEx(pSSM, &IgnDesc, sizeof(IgnDesc), 0 /* fFlags */, g_aSSMBDLEDescFields7, NULL);
4033 AssertRCReturn(rc, rc);
4034
4035 HDABDLESTATELEGACY IgnState;
4036 rc = pHlp->pfnSSMGetStructEx(pSSM, &IgnState, sizeof(IgnState), 0 /* fFlags */, g_aSSMBDLEStateFields7, NULL);
4037 AssertRCReturn(rc, rc);
4038
4039 Log2Func(("[SD%RU8]\n", pStreamShared->u8SD));
4040
4041 /*
4042 * Load period state if present.
4043 */
4044 if (uVersion < HDA_SAVED_STATE_WITHOUT_PERIOD)
4045 {
4046 static SSMFIELD const s_aSSMStreamPeriodFields7[] = /* For the removed HDASTREAMPERIOD structure. */
4047 {
4048 SSMFIELD_ENTRY_OLD(u64StartWalClk, sizeof(uint64_t)),
4049 SSMFIELD_ENTRY_OLD(u64ElapsedWalClk, sizeof(uint64_t)),
4050 SSMFIELD_ENTRY_OLD(cFramesTransferred, sizeof(uint32_t)),
4051 SSMFIELD_ENTRY_OLD(cIntPending, sizeof(uint8_t)), /** @todo Not sure what we should for non-zero values on restore... ignoring it for now. */
4052 SSMFIELD_ENTRY_TERM()
4053 };
4054 uint8_t bWhatever = 0;
4055 rc = pHlp->pfnSSMGetStructEx(pSSM, &bWhatever, sizeof(bWhatever), 0 /* fFlags */, s_aSSMStreamPeriodFields7, NULL);
4056 AssertRCReturn(rc, rc);
4057 }
4058
4059 /*
4060 * Load internal DMA buffer.
4061 */
4062 uint32_t cbCircBuf = 0;
4063 pHlp->pfnSSMGetU32(pSSM, &cbCircBuf); /* cbCircBuf */
4064 uint32_t cbCircBufUsed = 0;
4065 rc = pHlp->pfnSSMGetU32(pSSM, &cbCircBufUsed); /* cbCircBuf */
4066 AssertRCReturn(rc, rc);
4067
4068 if (cbCircBuf) /* If 0, skip the buffer. */
4069 {
4070 /* Paranoia. */
4071 AssertLogRelMsgReturn(cbCircBuf <= _32M,
4072 ("HDA: Saved state contains bogus DMA buffer size (%RU32) for stream #%RU8",
4073 cbCircBuf, idStream),
4074 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
4075 AssertLogRelMsgReturn(cbCircBufUsed <= cbCircBuf,
4076 ("HDA: Saved state contains invalid DMA buffer usage (%RU32/%RU32) for stream #%RU8",
4077 cbCircBufUsed, cbCircBuf, idStream),
4078 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
4079
4080 /* Do we need to cre-create the circular buffer do fit the data size? */
4081 if ( pStreamR3->State.pCircBuf
4082 && cbCircBuf != (uint32_t)RTCircBufSize(pStreamR3->State.pCircBuf))
4083 {
4084 RTCircBufDestroy(pStreamR3->State.pCircBuf);
4085 pStreamR3->State.pCircBuf = NULL;
4086 }
4087
4088 rc = RTCircBufCreate(&pStreamR3->State.pCircBuf, cbCircBuf);
4089 AssertRCReturn(rc, rc);
4090 pStreamR3->State.StatDmaBufSize = cbCircBuf;
4091
4092 if (cbCircBufUsed)
4093 {
4094 void *pvBuf = NULL;
4095 size_t cbBuf = 0;
4096 RTCircBufAcquireWriteBlock(pStreamR3->State.pCircBuf, cbCircBufUsed, &pvBuf, &cbBuf);
4097
4098 AssertLogRelMsgReturn(cbBuf == cbCircBufUsed, ("cbBuf=%zu cbCircBufUsed=%zu\n", cbBuf, cbCircBufUsed),
4099 VERR_INTERNAL_ERROR_3);
4100 rc = pHlp->pfnSSMGetMem(pSSM, pvBuf, cbBuf);
4101 AssertRCReturn(rc, rc);
4102 pStreamShared->State.offWrite = cbCircBufUsed;
4103
4104 RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbBuf);
4105
4106 Assert(cbBuf == cbCircBufUsed);
4107 }
4108 }
4109
4110 Log2Func(("[SD%RU8] LPIB=%RU32, CBL=%RU32, LVI=%RU32\n", idStream, HDA_STREAM_REG(pThis, LPIB, idStream),
4111 HDA_STREAM_REG(pThis, CBL, idStream), HDA_STREAM_REG(pThis, LVI, idStream)));
4112#ifdef LOG_ENABLED
4113 hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
4114#endif
4115 /** @todo (Re-)initialize active periods? */
4116
4117 } /* for cStreams */
4118
4119 LogFlowFuncLeaveRC(rc);
4120 return rc;
4121}
4122
4123
4124/*********************************************************************************************************************************
4125* IPRT format type handlers *
4126*********************************************************************************************************************************/
4127
4128/**
4129 * @callback_method_impl{FNRTSTRFORMATTYPE}
4130 */
4131static DECLCALLBACK(size_t) hdaR3StrFmtSDCTL(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
4132 const char *pszType, void const *pvValue,
4133 int cchWidth, int cchPrecision, unsigned fFlags,
4134 void *pvUser)
4135{
4136 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
4137 uint32_t uSDCTL = (uint32_t)(uintptr_t)pvValue;
4138 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
4139 "SDCTL(raw:%#x, DIR:%s, TP:%RTbool, STRIPE:%x, DEIE:%RTbool, FEIE:%RTbool, IOCE:%RTbool, RUN:%RTbool, RESET:%RTbool)",
4140 uSDCTL,
4141 uSDCTL & HDA_SDCTL_DIR ? "OUT" : "IN",
4142 RT_BOOL(uSDCTL & HDA_SDCTL_TP),
4143 (uSDCTL & HDA_SDCTL_STRIPE_MASK) >> HDA_SDCTL_STRIPE_SHIFT,
4144 RT_BOOL(uSDCTL & HDA_SDCTL_DEIE),
4145 RT_BOOL(uSDCTL & HDA_SDCTL_FEIE),
4146 RT_BOOL(uSDCTL & HDA_SDCTL_IOCE),
4147 RT_BOOL(uSDCTL & HDA_SDCTL_RUN),
4148 RT_BOOL(uSDCTL & HDA_SDCTL_SRST));
4149}
4150
4151/**
4152 * @callback_method_impl{FNRTSTRFORMATTYPE}
4153 */
4154static DECLCALLBACK(size_t) hdaR3StrFmtSDFIFOS(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
4155 const char *pszType, void const *pvValue,
4156 int cchWidth, int cchPrecision, unsigned fFlags,
4157 void *pvUser)
4158{
4159 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
4160 uint32_t uSDFIFOS = (uint32_t)(uintptr_t)pvValue;
4161 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOS(raw:%#x, sdfifos:%RU8 B)", uSDFIFOS, uSDFIFOS ? uSDFIFOS + 1 : 0);
4162}
4163
4164/**
4165 * @callback_method_impl{FNRTSTRFORMATTYPE}
4166 */
4167static DECLCALLBACK(size_t) hdaR3StrFmtSDFIFOW(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
4168 const char *pszType, void const *pvValue,
4169 int cchWidth, int cchPrecision, unsigned fFlags,
4170 void *pvUser)
4171{
4172 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
4173 uint32_t uSDFIFOW = (uint32_t)(uintptr_t)pvValue;
4174 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOW(raw: %#0x, sdfifow:%d B)", uSDFIFOW, hdaSDFIFOWToBytes(uSDFIFOW));
4175}
4176
4177/**
4178 * @callback_method_impl{FNRTSTRFORMATTYPE}
4179 */
4180static DECLCALLBACK(size_t) hdaR3StrFmtSDSTS(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
4181 const char *pszType, void const *pvValue,
4182 int cchWidth, int cchPrecision, unsigned fFlags,
4183 void *pvUser)
4184{
4185 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
4186 uint32_t uSdSts = (uint32_t)(uintptr_t)pvValue;
4187 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
4188 "SDSTS(raw:%#0x, fifordy:%RTbool, dese:%RTbool, fifoe:%RTbool, bcis:%RTbool)",
4189 uSdSts,
4190 RT_BOOL(uSdSts & HDA_SDSTS_FIFORDY),
4191 RT_BOOL(uSdSts & HDA_SDSTS_DESE),
4192 RT_BOOL(uSdSts & HDA_SDSTS_FIFOE),
4193 RT_BOOL(uSdSts & HDA_SDSTS_BCIS));
4194}
4195
4196
4197/*********************************************************************************************************************************
4198* Debug Info Item Handlers *
4199*********************************************************************************************************************************/
4200
4201/** Worker for hdaR3DbgInfo. */
4202static int hdaR3DbgLookupRegByName(const char *pszArgs)
4203{
4204 if (pszArgs && *pszArgs != '\0')
4205 for (int iReg = 0; iReg < HDA_NUM_REGS; ++iReg)
4206 if (!RTStrICmp(g_aHdaRegMap[iReg].pszName, pszArgs))
4207 return iReg;
4208 return -1;
4209}
4210
4211/** Worker for hdaR3DbgInfo. */
4212static void hdaR3DbgPrintRegister(PPDMDEVINS pDevIns, PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaIndex)
4213{
4214 /** @todo HDA_REG_IDX_NOMEM & GCAP both uses idxReg zero, no flag or anything
4215 * to tell them appart. */
4216 if (g_aHdaRegMap[iHdaIndex].idxReg != 0 || g_aHdaRegMap[iHdaIndex].pfnRead != hdaRegReadWALCLK)
4217 pHlp->pfnPrintf(pHlp, "%s: 0x%x\n", g_aHdaRegMap[iHdaIndex].pszName, pThis->au32Regs[g_aHdaRegMap[iHdaIndex].idxReg]);
4218 else
4219 {
4220 uint64_t uWallNow = 0;
4221 hdaQueryWallClock(pDevIns, pThis, false /*fDoDma*/, &uWallNow);
4222 pHlp->pfnPrintf(pHlp, "%s: 0x%RX64\n", g_aHdaRegMap[iHdaIndex].pszName, uWallNow);
4223 }
4224}
4225
4226/**
4227 * @callback_method_impl{FNDBGFHANDLERDEV}
4228 */
4229static DECLCALLBACK(void) hdaR3DbgInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4230{
4231 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4232 int idxReg = hdaR3DbgLookupRegByName(pszArgs);
4233 if (idxReg != -1)
4234 hdaR3DbgPrintRegister(pDevIns, pThis, pHlp, idxReg);
4235 else
4236 for (idxReg = 0; idxReg < HDA_NUM_REGS; ++idxReg)
4237 hdaR3DbgPrintRegister(pDevIns, pThis, pHlp, idxReg);
4238}
4239
4240/** Worker for hdaR3DbgInfoStream. */
4241static void hdaR3DbgPrintStream(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int idxStream)
4242{
4243 char szTmp[PDMAUDIOSTRMCFGTOSTRING_MAX];
4244 PHDASTREAM const pStream = &pThis->aStreams[idxStream];
4245 pHlp->pfnPrintf(pHlp, "Stream #%d: %s\n", idxStream, PDMAudioStrmCfgToString(&pStream->State.Cfg, szTmp, sizeof(szTmp)));
4246 pHlp->pfnPrintf(pHlp, " SD%dCTL : %R[sdctl]\n", idxStream, HDA_STREAM_REG(pThis, CTL, idxStream));
4247 pHlp->pfnPrintf(pHlp, " SD%dCTS : %R[sdsts]\n", idxStream, HDA_STREAM_REG(pThis, STS, idxStream));
4248 pHlp->pfnPrintf(pHlp, " SD%dFIFOS: %R[sdfifos]\n", idxStream, HDA_STREAM_REG(pThis, FIFOS, idxStream));
4249 pHlp->pfnPrintf(pHlp, " SD%dFIFOW: %R[sdfifow]\n", idxStream, HDA_STREAM_REG(pThis, FIFOW, idxStream));
4250 pHlp->pfnPrintf(pHlp, " Current BDLE%02u: %s%#RX64 LB %#x%s - off=%#x\n", pStream->State.idxCurBdle, "%%" /*vboxdbg phys prefix*/,
4251 pStream->State.aBdl[pStream->State.idxCurBdle].GCPhys, pStream->State.aBdl[pStream->State.idxCurBdle].cb,
4252 pStream->State.aBdl[pStream->State.idxCurBdle].fFlags ? " IOC" : "", pStream->State.offCurBdle);
4253}
4254
4255/** Worker for hdaR3DbgInfoBDL. */
4256static void hdaR3DbgPrintBDL(PPDMDEVINS pDevIns, PHDASTATE pThis, PCDBGFINFOHLP pHlp, int idxStream)
4257{
4258 const PHDASTREAM pStream = &pThis->aStreams[idxStream];
4259 PCPDMAUDIOPCMPROPS pProps = &pStream->State.Cfg.Props;
4260 uint64_t const u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, idxStream),
4261 HDA_STREAM_REG(pThis, BDPU, idxStream));
4262 uint16_t const u16LVI = HDA_STREAM_REG(pThis, LVI, idxStream);
4263 uint32_t const u32CBL = HDA_STREAM_REG(pThis, CBL, idxStream);
4264 uint8_t const idxCurBdle = pStream->State.idxCurBdle;
4265 pHlp->pfnPrintf(pHlp, "Stream #%d BDL: %s%#011RX64 LB %#x (LVI=%u)\n", idxStream, "%%" /*vboxdbg phys prefix*/,
4266 u64BaseDMA, u16LVI * sizeof(HDABDLEDESC), u16LVI);
4267 if (u64BaseDMA || idxCurBdle != 0 || pStream->State.aBdl[idxCurBdle].GCPhys != 0 || pStream->State.aBdl[idxCurBdle].cb != 0)
4268 pHlp->pfnPrintf(pHlp, " Current: BDLE%03u: %s%#011RX64 LB %#x%s - off=%#x LPIB=%#RX32\n",
4269 pStream->State.idxCurBdle, "%%" /*vboxdbg phys prefix*/,
4270 pStream->State.aBdl[idxCurBdle].GCPhys, pStream->State.aBdl[idxCurBdle].cb,
4271 pStream->State.aBdl[idxCurBdle].fFlags ? " IOC" : "", pStream->State.offCurBdle,
4272 HDA_STREAM_REG(pThis, LPIB, idxStream));
4273 if (!u64BaseDMA)
4274 return;
4275
4276 /*
4277 * The BDL:
4278 */
4279 uint64_t cbTotal = 0;
4280 for (uint16_t i = 0; i < u16LVI + 1; i++)
4281 {
4282 HDABDLEDESC bd = {0, 0, 0};
4283 PDMDevHlpPCIPhysRead(pDevIns, u64BaseDMA + i * sizeof(HDABDLEDESC), &bd, sizeof(bd));
4284
4285 char szFlags[64];
4286 szFlags[0] = '\0';
4287 if (bd.fFlags & ~HDA_BDLE_F_IOC)
4288 RTStrPrintf(szFlags, sizeof(szFlags), " !!fFlags=%#x!!\n", bd.fFlags);
4289 pHlp->pfnPrintf(pHlp, " %sBDLE%03u: %s%#011RX64 LB %#06x (%RU64 us) %s%s\n", idxCurBdle == i ? "=>" : " ", i, "%%",
4290 bd.u64BufAddr, bd.u32BufSize, PDMAudioPropsBytesToMicro(pProps, bd.u32BufSize),
4291 bd.fFlags & HDA_BDLE_F_IOC ? " IOC=1" : "", szFlags);
4292
4293 if (memcmp(&bd, &pStream->State.aBdl[i], sizeof(bd)) != 0)
4294 {
4295 szFlags[0] = '\0';
4296 if (bd.fFlags & ~HDA_BDLE_F_IOC)
4297 RTStrPrintf(szFlags, sizeof(szFlags), " !!fFlags=%#x!!\n", bd.fFlags);
4298 pHlp->pfnPrintf(pHlp, " !!!loaded: %s%#011RX64 LB %#06x %s%s\n", "%%", pStream->State.aBdl[i].GCPhys,
4299 pStream->State.aBdl[i].cb, pStream->State.aBdl[i].fFlags & HDA_BDLE_F_IOC ? " IOC=1" : "", szFlags);
4300 }
4301
4302 cbTotal += bd.u32BufSize;
4303 }
4304 pHlp->pfnPrintf(pHlp, " Total: %#RX64 bytes (%RU64), %RU64 ms\n", cbTotal, cbTotal,
4305 PDMAudioPropsBytesToMilli(pProps, (uint32_t)cbTotal));
4306 if (cbTotal != u32CBL)
4307 pHlp->pfnPrintf(pHlp, " Warning: %#RX64 bytes does not match CBL (%#RX64)!\n", cbTotal, u32CBL);
4308
4309 /*
4310 * The scheduling plan.
4311 */
4312 uint16_t const idxSchedule = pStream->State.idxSchedule;
4313 pHlp->pfnPrintf(pHlp, " Scheduling: %u items, %u prologue. Current: %u, loop %u.\n", pStream->State.cSchedule,
4314 pStream->State.cSchedulePrologue, idxSchedule, pStream->State.idxScheduleLoop);
4315 for (uint16_t i = 0; i < pStream->State.cSchedule; i++)
4316 pHlp->pfnPrintf(pHlp, " %s#%02u: %#x bytes, %u loop%s, %RU32 ticks. BDLE%u thru BDLE%u\n",
4317 i == idxSchedule ? "=>" : " ", i,
4318 pStream->State.aSchedule[i].cbPeriod, pStream->State.aSchedule[i].cLoops,
4319 pStream->State.aSchedule[i].cLoops == 1 ? "" : "s",
4320 pStream->State.aSchedule[i].cPeriodTicks, pStream->State.aSchedule[i].idxFirst,
4321 pStream->State.aSchedule[i].idxFirst + pStream->State.aSchedule[i].cEntries - 1);
4322}
4323
4324/** Used by hdaR3DbgInfoStream and hdaR3DbgInfoBDL. */
4325static int hdaR3DbgLookupStrmIdx(PCDBGFINFOHLP pHlp, const char *pszArgs)
4326{
4327 if (pszArgs && *pszArgs)
4328 {
4329 int32_t idxStream;
4330 int rc = RTStrToInt32Full(pszArgs, 0, &idxStream);
4331 if (RT_SUCCESS(rc) && idxStream >= -1 && idxStream < HDA_MAX_STREAMS)
4332 return idxStream;
4333 pHlp->pfnPrintf(pHlp, "Argument '%s' is not a valid stream number!\n", pszArgs);
4334 }
4335 return -1;
4336}
4337
4338/**
4339 * @callback_method_impl{FNDBGFHANDLERDEV, hdastream}
4340 */
4341static DECLCALLBACK(void) hdaR3DbgInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4342{
4343 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4344 int idxStream = hdaR3DbgLookupStrmIdx(pHlp, pszArgs);
4345 if (idxStream != -1)
4346 hdaR3DbgPrintStream(pThis, pHlp, idxStream);
4347 else
4348 for (idxStream = 0; idxStream < HDA_MAX_STREAMS; ++idxStream)
4349 hdaR3DbgPrintStream(pThis, pHlp, idxStream);
4350}
4351
4352/**
4353 * @callback_method_impl{FNDBGFHANDLERDEV, hdabdl}
4354 */
4355static DECLCALLBACK(void) hdaR3DbgInfoBDL(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4356{
4357 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4358 int idxStream = hdaR3DbgLookupStrmIdx(pHlp, pszArgs);
4359 if (idxStream != -1)
4360 hdaR3DbgPrintBDL(pDevIns, pThis, pHlp, idxStream);
4361 else
4362 {
4363 for (idxStream = 0; idxStream < HDA_MAX_STREAMS; ++idxStream)
4364 hdaR3DbgPrintBDL(pDevIns, pThis, pHlp, idxStream);
4365 idxStream = -1;
4366 }
4367
4368 /*
4369 * DMA stream positions:
4370 */
4371 uint64_t const uDPBase = pThis->u64DPBase & DPBASE_ADDR_MASK;
4372 pHlp->pfnPrintf(pHlp, "DMA counters %#011RX64 LB %#x, %s:\n", uDPBase, HDA_MAX_STREAMS * 2 * sizeof(uint32_t),
4373 pThis->fDMAPosition ? "enabled" : "disabled");
4374 if (uDPBase)
4375 {
4376 struct
4377 {
4378 uint32_t off, uReserved;
4379 } aPositions[HDA_MAX_STREAMS];
4380 RT_ZERO(aPositions);
4381 PDMDevHlpPCIPhysRead(pDevIns, uDPBase , &aPositions[0], sizeof(aPositions));
4382
4383 for (unsigned i = 0; i < RT_ELEMENTS(aPositions); i++)
4384 if (idxStream == -1 || i == (unsigned)idxStream) /* lazy bird */
4385 {
4386 char szReserved[64];
4387 szReserved[0] = '\0';
4388 if (aPositions[i].uReserved != 0)
4389 RTStrPrintf(szReserved, sizeof(szReserved), " reserved=%#x", aPositions[i].uReserved);
4390 pHlp->pfnPrintf(pHlp, " Stream #%u DMA @ %#x%s\n", i, aPositions[i].off, szReserved);
4391 }
4392 }
4393}
4394
4395/**
4396 * @callback_method_impl{FNDBGFHANDLERDEV, hdcnodes}
4397 */
4398static DECLCALLBACK(void) hdaR3DbgInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4399{
4400 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4401 hdaR3CodecDbgListNodes(&pThisCC->Codec, pHlp, pszArgs);
4402}
4403
4404/**
4405 * @callback_method_impl{FNDBGFHANDLERDEV, hdcselector}
4406 */
4407static DECLCALLBACK(void) hdaR3DbgInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4408{
4409 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4410 hdaR3CodecDbgSelector(&pThisCC->Codec, pHlp, pszArgs);
4411}
4412
4413/**
4414 * @callback_method_impl{FNDBGFHANDLERDEV, hdamixer}
4415 */
4416static DECLCALLBACK(void) hdaR3DbgInfoMixer(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4417{
4418 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4419 if (pThisCC->pMixer)
4420 AudioMixerDebug(pThisCC->pMixer, pHlp, pszArgs);
4421 else
4422 pHlp->pfnPrintf(pHlp, "Mixer not available\n");
4423}
4424
4425
4426/*********************************************************************************************************************************
4427* PDMIBASE *
4428*********************************************************************************************************************************/
4429
4430/**
4431 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4432 */
4433static DECLCALLBACK(void *) hdaR3QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
4434{
4435 PHDASTATER3 pThisCC = RT_FROM_MEMBER(pInterface, HDASTATER3, IBase);
4436
4437 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
4438 return NULL;
4439}
4440
4441
4442/*********************************************************************************************************************************
4443* PDMDEVREGR3 *
4444*********************************************************************************************************************************/
4445
4446/**
4447 * Worker for hdaR3Construct() and hdaR3Attach().
4448 *
4449 * @returns VBox status code.
4450 * @param pDevIns The device instance.
4451 * @param pThis The shared HDA device state.
4452 * @param pThisCC The ring-3 HDA device state.
4453 * @param uLUN The logical unit which is being detached.
4454 * @param ppDrv Attached driver instance on success. Optional.
4455 */
4456static int hdaR3AttachInternal(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, unsigned uLUN, PHDADRIVER *ppDrv)
4457{
4458 /*
4459 * Attach driver.
4460 */
4461 char *pszDesc = RTStrAPrintf2("Audio driver port (HDA) for LUN#%u", uLUN);
4462 AssertLogRelReturn(pszDesc, VERR_NO_STR_MEMORY);
4463
4464 PPDMIBASE pDrvBase;
4465 int rc = PDMDevHlpDriverAttach(pDevIns, uLUN, &pThisCC->IBase, &pDrvBase, pszDesc);
4466 if (RT_SUCCESS(rc))
4467 {
4468 PHDADRIVER pDrv = (PHDADRIVER)RTMemAllocZ(sizeof(HDADRIVER));
4469 if (pDrv)
4470 {
4471 pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
4472 AssertPtr(pDrv->pConnector);
4473 if (RT_VALID_PTR(pDrv->pConnector))
4474 {
4475 pDrv->pDrvBase = pDrvBase;
4476 pDrv->pHDAStateShared = pThis;
4477 pDrv->pHDAStateR3 = pThisCC;
4478 pDrv->uLUN = uLUN;
4479
4480 /* Attach to driver list if not attached yet. */
4481 if (!pDrv->fAttached)
4482 {
4483 RTListAppend(&pThisCC->lstDrv, &pDrv->Node);
4484 pDrv->fAttached = true;
4485 }
4486
4487 if (ppDrv)
4488 *ppDrv = pDrv;
4489
4490 /*
4491 * While we're here, give the windows backends a hint about our typical playback
4492 * configuration.
4493 * Note! If 48000Hz is advertised to the guest, add it here.
4494 */
4495 if ( pDrv->pConnector
4496 && pDrv->pConnector->pfnStreamConfigHint)
4497 {
4498 PDMAUDIOSTREAMCFG Cfg;
4499 RT_ZERO(Cfg);
4500 Cfg.enmDir = PDMAUDIODIR_OUT;
4501 Cfg.enmPath = PDMAUDIOPATH_OUT_FRONT;
4502 Cfg.Device.cMsSchedulingHint = 10;
4503 Cfg.Backend.cFramesPreBuffering = UINT32_MAX;
4504 PDMAudioPropsInit(&Cfg.Props, 2, true /*fSigned*/, 2, 44100);
4505 RTStrPrintf(Cfg.szName, sizeof(Cfg.szName), "output 44.1kHz 2ch S16 (HDA config hint)");
4506
4507 pDrv->pConnector->pfnStreamConfigHint(pDrv->pConnector, &Cfg); /* (may trash CfgReq) */
4508 }
4509
4510 LogFunc(("LUN#%u: returns VINF_SUCCESS (pCon=%p)\n", uLUN, pDrv->pConnector));
4511 return VINF_SUCCESS;
4512 }
4513
4514 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
4515 }
4516 else
4517 rc = VERR_NO_MEMORY;
4518 }
4519 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4520 LogFunc(("No attached driver for LUN #%u\n", uLUN));
4521 else
4522 LogFunc(("Failed attaching driver for LUN #%u: %Rrc\n", uLUN, rc));
4523
4524 RTStrFree(pszDesc);
4525 LogFunc(("LUN#%u: rc=%Rrc\n", uLUN, rc));
4526 return rc;
4527}
4528
4529
4530/**
4531 * @interface_method_impl{PDMDEVREG,pfnAttach}
4532 */
4533static DECLCALLBACK(int) hdaR3Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
4534{
4535 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4536 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4537 RT_NOREF(fFlags);
4538 LogFunc(("uLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
4539
4540 DEVHDA_LOCK_RETURN(pDevIns, pThis, VERR_IGNORED);
4541
4542 PHDADRIVER pDrv;
4543 int rc = hdaR3AttachInternal(pDevIns, pThis, pThisCC, uLUN, &pDrv);
4544 if (RT_SUCCESS(rc))
4545 {
4546 int rc2 = hdaR3MixerAddDrv(pDevIns, pThisCC, pDrv);
4547 if (RT_FAILURE(rc2))
4548 LogFunc(("hdaR3MixerAddDrv failed with %Rrc (ignored)\n", rc2));
4549 }
4550
4551 DEVHDA_UNLOCK(pDevIns, pThis);
4552 return rc;
4553}
4554
4555
4556/**
4557 * Worker for hdaR3Detach that does all but free pDrv.
4558 *
4559 * This is called to let the device detach from a driver for a specified LUN
4560 * at runtime.
4561 *
4562 * @param pDevIns The device instance.
4563 * @param pThisCC The ring-3 HDA device state.
4564 * @param pDrv Driver to detach from device.
4565 */
4566static void hdaR3DetachInternal(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PHDADRIVER pDrv)
4567{
4568 /* Remove the driver from our list and destory it's associated streams.
4569 This also will un-set the driver as a recording source (if associated). */
4570 hdaR3MixerRemoveDrv(pDevIns, pThisCC, pDrv);
4571 LogFunc(("LUN#%u detached\n", pDrv->uLUN));
4572}
4573
4574
4575/**
4576 * @interface_method_impl{PDMDEVREG,pfnDetach}
4577 */
4578static DECLCALLBACK(void) hdaR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4579{
4580 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4581 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4582 RT_NOREF(fFlags);
4583 LogFunc(("iLUN=%u, fFlags=%#x\n", iLUN, fFlags));
4584
4585 DEVHDA_LOCK(pDevIns, pThis);
4586
4587 PHDADRIVER pDrv;
4588 RTListForEach(&pThisCC->lstDrv, pDrv, HDADRIVER, Node)
4589 {
4590 if (pDrv->uLUN == iLUN)
4591 {
4592 hdaR3DetachInternal(pDevIns, pThisCC, pDrv);
4593 RTMemFree(pDrv);
4594 DEVHDA_UNLOCK(pDevIns, pThis);
4595 return;
4596 }
4597 }
4598
4599 DEVHDA_UNLOCK(pDevIns, pThis);
4600 LogFunc(("LUN#%u was not found\n", iLUN));
4601}
4602
4603
4604/**
4605 * Powers off the device.
4606 *
4607 * @param pDevIns Device instance to power off.
4608 */
4609static DECLCALLBACK(void) hdaR3PowerOff(PPDMDEVINS pDevIns)
4610{
4611 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4612 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4613
4614 DEVHDA_LOCK_RETURN_VOID(pDevIns, pThis);
4615
4616 LogRel2(("HDA: Powering off ...\n"));
4617
4618/** @todo r=bird: What this "releasing references" and whatever here is
4619 * referring to, is apparently that the device is destroyed after the
4620 * drivers, so creating trouble as those structures have been torn down
4621 * already... Reverse order, like we do for power off? Need a new
4622 * PDMDEVREG flag. */
4623
4624 /* Ditto goes for the codec, which in turn uses the mixer. */
4625 hdaR3CodecPowerOff(&pThisCC->Codec);
4626
4627 /* This is to prevent us from calling into the mixer and mixer sink code
4628 after it has been destroyed below. */
4629 for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
4630 pThisCC->aStreams[i].State.pAioRegSink = NULL; /* don't need to remove, we're destorying it. */
4631
4632 /*
4633 * Note: Destroy the mixer while powering off and *not* in hdaR3Destruct,
4634 * giving the mixer the chance to release any references held to
4635 * PDM audio streams it maintains.
4636 */
4637 if (pThisCC->pMixer)
4638 {
4639 AudioMixerDestroy(pThisCC->pMixer, pDevIns);
4640 pThisCC->pMixer = NULL;
4641 }
4642
4643 DEVHDA_UNLOCK(pDevIns, pThis);
4644}
4645
4646
4647/**
4648 * @interface_method_impl{PDMDEVREG,pfnReset}
4649 */
4650static DECLCALLBACK(void) hdaR3Reset(PPDMDEVINS pDevIns)
4651{
4652 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4653 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4654
4655 LogFlowFuncEnter();
4656
4657 DEVHDA_LOCK_RETURN_VOID(pDevIns, pThis);
4658
4659 /*
4660 * 18.2.6,7 defines that values of this registers might be cleared on power on/reset
4661 * hdaR3Reset shouldn't affects these registers.
4662 */
4663 HDA_REG(pThis, WAKEEN) = 0x0;
4664
4665 hdaR3GCTLReset(pDevIns, pThis, pThisCC);
4666
4667 /* Indicate that HDA is not in reset. The firmware is supposed to (un)reset HDA,
4668 * but we can take a shortcut.
4669 */
4670 HDA_REG(pThis, GCTL) = HDA_GCTL_CRST;
4671
4672 DEVHDA_UNLOCK(pDevIns, pThis);
4673}
4674
4675
4676/**
4677 * @interface_method_impl{PDMDEVREG,pfnDestruct}
4678 */
4679static DECLCALLBACK(int) hdaR3Destruct(PPDMDEVINS pDevIns)
4680{
4681 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); /* this shall come first */
4682 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4683 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4684
4685 if (PDMCritSectIsInitialized(&pThis->CritSect))
4686 PDMCritSectEnter(&pThis->CritSect, VERR_IGNORED);
4687
4688 PHDADRIVER pDrv;
4689 while (!RTListIsEmpty(&pThisCC->lstDrv))
4690 {
4691 pDrv = RTListGetFirst(&pThisCC->lstDrv, HDADRIVER, Node);
4692
4693 RTListNodeRemove(&pDrv->Node);
4694 RTMemFree(pDrv);
4695 }
4696
4697 hdaCodecDestruct(&pThisCC->Codec);
4698
4699 for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
4700 hdaR3StreamDestroy(&pThisCC->aStreams[i]);
4701
4702 /* We don't always go via PowerOff, so make sure the mixer is destroyed. */
4703 if (pThisCC->pMixer)
4704 {
4705 AudioMixerDestroy(pThisCC->pMixer, pDevIns);
4706 pThisCC->pMixer = NULL;
4707 }
4708
4709 if (PDMCritSectIsInitialized(&pThis->CritSect))
4710 {
4711 PDMCritSectLeave(&pThis->CritSect);
4712 PDMR3CritSectDelete(&pThis->CritSect);
4713 }
4714 return VINF_SUCCESS;
4715}
4716
4717
4718/**
4719 * @interface_method_impl{PDMDEVREG,pfnConstruct}
4720 */
4721static DECLCALLBACK(int) hdaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
4722{
4723 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* this shall come first */
4724 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4725 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4726 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4727 Assert(iInstance == 0); RT_NOREF(iInstance);
4728
4729 /*
4730 * Initialize the state sufficently to make the destructor work.
4731 */
4732 pThis->uAlignmentCheckMagic = HDASTATE_ALIGNMENT_CHECK_MAGIC;
4733 RTListInit(&pThisCC->lstDrv);
4734 pThis->cbCorbBuf = HDA_CORB_SIZE * HDA_CORB_ELEMENT_SIZE;
4735 pThis->cbRirbBuf = HDA_RIRB_SIZE * HDA_RIRB_ELEMENT_SIZE;
4736 pThis->hCorbDmaTask = NIL_PDMTASKHANDLE;
4737
4738 /** @todo r=bird: There are probably other things which should be
4739 * initialized here before we start failing. */
4740
4741 /*
4742 * Validate and read configuration.
4743 */
4744 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
4745 "BufSizeInMs"
4746 "|BufSizeOutMs"
4747 "|DebugEnabled"
4748 "|DebugPathOut",
4749 "");
4750
4751 /** @devcfgm{hda,BufSizeInMs,uint16_t,0,2000,0,ms}
4752 * The size of the DMA buffer for input streams expressed in milliseconds. */
4753 int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeInMs", &pThis->cMsCircBufIn, 0);
4754 if (RT_FAILURE(rc))
4755 return PDMDEV_SET_ERROR(pDevIns, rc,
4756 N_("HDA configuration error: failed to read 'BufSizeInMs' as 16-bit unsigned integer"));
4757 if (pThis->cMsCircBufIn > 2000)
4758 return PDMDEV_SET_ERROR(pDevIns, VERR_OUT_OF_RANGE,
4759 N_("HDA configuration error: 'BufSizeInMs' is out of bound, max 2000 ms"));
4760
4761 /** @devcfgm{hda,BufSizeOutMs,uint16_t,0,2000,0,ms}
4762 * The size of the DMA buffer for output streams expressed in milliseconds. */
4763 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeOutMs", &pThis->cMsCircBufOut, 0);
4764 if (RT_FAILURE(rc))
4765 return PDMDEV_SET_ERROR(pDevIns, rc,
4766 N_("HDA configuration error: failed to read 'BufSizeOutMs' as 16-bit unsigned integer"));
4767 if (pThis->cMsCircBufOut > 2000)
4768 return PDMDEV_SET_ERROR(pDevIns, VERR_OUT_OF_RANGE,
4769 N_("HDA configuration error: 'BufSizeOutMs' is out of bound, max 2000 ms"));
4770
4771 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DebugEnabled", &pThisCC->Dbg.fEnabled, false);
4772 if (RT_FAILURE(rc))
4773 return PDMDEV_SET_ERROR(pDevIns, rc,
4774 N_("HDA configuration error: failed to read debugging enabled flag as boolean"));
4775
4776 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "DebugPathOut", &pThisCC->Dbg.pszOutPath, NULL);
4777 if (RT_FAILURE(rc))
4778 return PDMDEV_SET_ERROR(pDevIns, rc,
4779 N_("HDA configuration error: failed to read debugging output path flag as string"));
4780 if (pThisCC->Dbg.fEnabled)
4781 LogRel2(("HDA: Debug output will be saved to '%s'\n", pThisCC->Dbg.pszOutPath));
4782
4783 /*
4784 * Use our own critical section for the device instead of the default
4785 * one provided by PDM. This allows fine-grained locking in combination
4786 * with TM when timer-specific stuff is being called in e.g. the MMIO handlers.
4787 */
4788 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "HDA");
4789 AssertRCReturn(rc, rc);
4790
4791 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
4792 AssertRCReturn(rc, rc);
4793
4794 /*
4795 * Initialize data (most of it anyway).
4796 */
4797 pThisCC->pDevIns = pDevIns;
4798 /* IBase */
4799 pThisCC->IBase.pfnQueryInterface = hdaR3QueryInterface;
4800
4801 /* PCI Device */
4802 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
4803 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
4804
4805 PDMPciDevSetVendorId( pPciDev, HDA_PCI_VENDOR_ID); /* nVidia */
4806 PDMPciDevSetDeviceId( pPciDev, HDA_PCI_DEVICE_ID); /* HDA */
4807
4808 PDMPciDevSetCommand( pPciDev, 0x0000); /* 04 rw,ro - pcicmd. */
4809 PDMPciDevSetStatus( pPciDev, VBOX_PCI_STATUS_CAP_LIST); /* 06 rwc?,ro? - pcists. */
4810 PDMPciDevSetRevisionId( pPciDev, 0x01); /* 08 ro - rid. */
4811 PDMPciDevSetClassProg( pPciDev, 0x00); /* 09 ro - pi. */
4812 PDMPciDevSetClassSub( pPciDev, 0x03); /* 0a ro - scc; 03 == HDA. */
4813 PDMPciDevSetClassBase( pPciDev, 0x04); /* 0b ro - bcc; 04 == multimedia. */
4814 PDMPciDevSetHeaderType( pPciDev, 0x00); /* 0e ro - headtyp. */
4815 PDMPciDevSetBaseAddress( pPciDev, 0, /* 10 rw - MMIO */
4816 false /* fIoSpace */, false /* fPrefetchable */, true /* f64Bit */, 0x00000000);
4817 PDMPciDevSetInterruptLine( pPciDev, 0x00); /* 3c rw. */
4818 PDMPciDevSetInterruptPin( pPciDev, 0x01); /* 3d ro - INTA#. */
4819
4820# if defined(HDA_AS_PCI_EXPRESS)
4821 PDMPciDevSetCapabilityList(pPciDev, 0x80);
4822# elif defined(VBOX_WITH_MSI_DEVICES)
4823 PDMPciDevSetCapabilityList(pPciDev, 0x60);
4824# else
4825 PDMPciDevSetCapabilityList(pPciDev, 0x50); /* ICH6 datasheet 18.1.16 */
4826# endif
4827
4828 /// @todo r=michaln: If there are really no PDMPciDevSetXx for these, the
4829 /// meaning of these values needs to be properly documented!
4830 /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
4831 PDMPciDevSetByte( pPciDev, 0x40, 0x01);
4832
4833 /* Power Management */
4834 PDMPciDevSetByte( pPciDev, 0x50 + 0, VBOX_PCI_CAP_ID_PM);
4835 PDMPciDevSetByte( pPciDev, 0x50 + 1, 0x0); /* next */
4836 PDMPciDevSetWord( pPciDev, 0x50 + 2, VBOX_PCI_PM_CAP_DSI | 0x02 /* version, PM1.1 */ );
4837
4838# ifdef HDA_AS_PCI_EXPRESS
4839 /* PCI Express */
4840 PDMPciDevSetByte( pPciDev, 0x80 + 0, VBOX_PCI_CAP_ID_EXP); /* PCI_Express */
4841 PDMPciDevSetByte( pPciDev, 0x80 + 1, 0x60); /* next */
4842 /* Device flags */
4843 PDMPciDevSetWord( pPciDev, 0x80 + 2,
4844 1 /* version */
4845 | (VBOX_PCI_EXP_TYPE_ROOT_INT_EP << 4) /* Root Complex Integrated Endpoint */
4846 | (100 << 9) /* MSI */ );
4847 /* Device capabilities */
4848 PDMPciDevSetDWord( pPciDev, 0x80 + 4, VBOX_PCI_EXP_DEVCAP_FLRESET);
4849 /* Device control */
4850 PDMPciDevSetWord( pPciDev, 0x80 + 8, 0);
4851 /* Device status */
4852 PDMPciDevSetWord( pPciDev, 0x80 + 10, 0);
4853 /* Link caps */
4854 PDMPciDevSetDWord( pPciDev, 0x80 + 12, 0);
4855 /* Link control */
4856 PDMPciDevSetWord( pPciDev, 0x80 + 16, 0);
4857 /* Link status */
4858 PDMPciDevSetWord( pPciDev, 0x80 + 18, 0);
4859 /* Slot capabilities */
4860 PDMPciDevSetDWord( pPciDev, 0x80 + 20, 0);
4861 /* Slot control */
4862 PDMPciDevSetWord( pPciDev, 0x80 + 24, 0);
4863 /* Slot status */
4864 PDMPciDevSetWord( pPciDev, 0x80 + 26, 0);
4865 /* Root control */
4866 PDMPciDevSetWord( pPciDev, 0x80 + 28, 0);
4867 /* Root capabilities */
4868 PDMPciDevSetWord( pPciDev, 0x80 + 30, 0);
4869 /* Root status */
4870 PDMPciDevSetDWord( pPciDev, 0x80 + 32, 0);
4871 /* Device capabilities 2 */
4872 PDMPciDevSetDWord( pPciDev, 0x80 + 36, 0);
4873 /* Device control 2 */
4874 PDMPciDevSetQWord( pPciDev, 0x80 + 40, 0);
4875 /* Link control 2 */
4876 PDMPciDevSetQWord( pPciDev, 0x80 + 48, 0);
4877 /* Slot control 2 */
4878 PDMPciDevSetWord( pPciDev, 0x80 + 56, 0);
4879# endif /* HDA_AS_PCI_EXPRESS */
4880
4881 /*
4882 * Register the PCI device.
4883 */
4884 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
4885 AssertRCReturn(rc, rc);
4886
4887 /** @todo r=bird: The IOMMMIO_FLAGS_READ_DWORD flag isn't entirely optimal,
4888 * as several frequently used registers aren't dword sized. 6.0 and earlier
4889 * will go to ring-3 to handle accesses to any such register, where-as 6.1 and
4890 * later will do trivial register reads in ring-0. Real optimal code would use
4891 * IOMMMIO_FLAGS_READ_PASSTHRU and do the necessary extra work to deal with
4892 * anything the guest may throw at us. */
4893 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 0, 0x4000, PCI_ADDRESS_SPACE_MEM, hdaMmioWrite, hdaMmioRead, NULL /*pvUser*/,
4894 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU, "HDA", &pThis->hMmio);
4895 AssertRCReturn(rc, rc);
4896
4897# ifdef VBOX_WITH_MSI_DEVICES
4898 PDMMSIREG MsiReg;
4899 RT_ZERO(MsiReg);
4900 MsiReg.cMsiVectors = 1;
4901 MsiReg.iMsiCapOffset = 0x60;
4902 MsiReg.iMsiNextOffset = 0x50;
4903 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
4904 if (RT_FAILURE(rc))
4905 {
4906 /* That's OK, we can work without MSI */
4907 PDMPciDevSetCapabilityList(pPciDev, 0x50);
4908 }
4909# endif
4910
4911 /* Create task for continuing CORB DMA in ring-3. */
4912 rc = PDMDevHlpTaskCreate(pDevIns, PDMTASK_F_RZ, "HDA CORB DMA",
4913 hdaR3CorbDmaTaskWorker, NULL /*pvUser*/, &pThis->hCorbDmaTask);
4914 AssertRCReturn(rc,rc);
4915
4916 rc = PDMDevHlpSSMRegisterEx(pDevIns, HDA_SAVED_STATE_VERSION, sizeof(*pThis), NULL /*pszBefore*/,
4917 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
4918 NULL /*pfnSavePrep*/, hdaR3SaveExec, NULL /*pfnSaveDone*/,
4919 NULL /*pfnLoadPrep*/, hdaR3LoadExec, hdaR3LoadDone);
4920 AssertRCReturn(rc, rc);
4921
4922 /*
4923 * Attach drivers. We ASSUME they are configured consecutively without any
4924 * gaps, so we stop when we hit the first LUN w/o a driver configured.
4925 */
4926 for (unsigned iLun = 0; ; iLun++)
4927 {
4928 AssertBreak(iLun < UINT8_MAX);
4929 LogFunc(("Trying to attach driver for LUN#%u ...\n", iLun));
4930 rc = hdaR3AttachInternal(pDevIns, pThis, pThisCC, iLun, NULL /* ppDrv */);
4931 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4932 {
4933 LogFunc(("cLUNs=%u\n", iLun));
4934 break;
4935 }
4936 AssertLogRelMsgReturn(RT_SUCCESS(rc), ("LUN#%u: rc=%Rrc\n", iLun, rc), rc);
4937 }
4938
4939 /*
4940 * Create the mixer.
4941 */
4942 uint32_t fMixer = AUDMIXER_FLAGS_NONE;
4943 if (pThisCC->Dbg.fEnabled)
4944 fMixer |= AUDMIXER_FLAGS_DEBUG;
4945 rc = AudioMixerCreate("HDA Mixer", fMixer, &pThisCC->pMixer);
4946 AssertRCReturn(rc, rc);
4947
4948 /*
4949 * Add mixer output sinks.
4950 */
4951# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
4952 rc = AudioMixerCreateSink(pThisCC->pMixer, "Front",
4953 PDMAUDIODIR_OUT, pDevIns, &pThisCC->SinkFront.pMixSink);
4954 AssertRCReturn(rc, rc);
4955 rc = AudioMixerCreateSink(pThisCC->pMixer, "Center+Subwoofer",
4956 PDMAUDIODIR_OUT, pDevIns, &pThisCC->SinkCenterLFE.pMixSink);
4957 AssertRCReturn(rc, rc);
4958 rc = AudioMixerCreateSink(pThisCC->pMixer, "Rear",
4959 PDMAUDIODIR_OUT, pDevIns, &pThisCC->SinkRear.pMixSink);
4960 AssertRCReturn(rc, rc);
4961# else
4962 rc = AudioMixerCreateSink(pThisCC->pMixer, "PCM Output",
4963 PDMAUDIODIR_OUT, pDevIns, &pThisCC->SinkFront.pMixSink);
4964 AssertRCReturn(rc, rc);
4965# endif /* VBOX_WITH_AUDIO_HDA_51_SURROUND */
4966
4967 /*
4968 * Add mixer input sinks.
4969 */
4970 rc = AudioMixerCreateSink(pThisCC->pMixer, "Line In",
4971 PDMAUDIODIR_IN, pDevIns, &pThisCC->SinkLineIn.pMixSink);
4972 AssertRCReturn(rc, rc);
4973# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
4974 rc = AudioMixerCreateSink(pThisCC->pMixer, "Microphone In",
4975 PDMAUDIODIR_IN, pDevIns, &pThisCC->SinkMicIn.pMixSink);
4976 AssertRCReturn(rc, rc);
4977# endif
4978
4979 /* There is no master volume control. Set the master to max. */
4980 PDMAUDIOVOLUME Vol = PDMAUDIOVOLUME_INITIALIZER_MAX;
4981 rc = AudioMixerSetMasterVolume(pThisCC->pMixer, &Vol);
4982 AssertRCReturn(rc, rc);
4983
4984 /*
4985 * Initialize the codec.
4986 */
4987 /* Construct the common + R3 codec part. */
4988 rc = hdaR3CodecConstruct(pDevIns, &pThisCC->Codec, 0 /* Codec index */, pCfg);
4989 AssertRCReturn(rc, rc);
4990
4991 /* ICH6 datasheet defines 0 values for SVID and SID (18.1.14-15), which together with values returned for
4992 verb F20 should provide device/codec recognition. */
4993 Assert(pThisCC->Codec.State.u16VendorId);
4994 Assert(pThisCC->Codec.State.u16DeviceId);
4995 PDMPciDevSetSubSystemVendorId(pPciDev, pThisCC->Codec.State.u16VendorId); /* 2c ro - intel.) */
4996 PDMPciDevSetSubSystemId( pPciDev, pThisCC->Codec.State.u16DeviceId); /* 2e ro. */
4997
4998 /*
4999 * Create the per stream timers and the asso.
5000 *
5001 * We must the critical section for the timers as the device has a
5002 * noop section associated with it.
5003 *
5004 * Note: Use TMCLOCK_VIRTUAL_SYNC here, as the guest's HDA driver relies
5005 * on exact (virtual) DMA timing and uses DMA Position Buffers
5006 * instead of the LPIB registers.
5007 */
5008 /** @todo r=bird: The need to use virtual sync is perhaps because TM
5009 * doesn't schedule regular TMCLOCK_VIRTUAL timers as accurately as it
5010 * should (VT-x preemption timer, etc). Hope to address that before
5011 * long. @bugref{9943}. */
5012 static const char * const s_apszNames[] =
5013 { "HDA SD0", "HDA SD1", "HDA SD2", "HDA SD3", "HDA SD4", "HDA SD5", "HDA SD6", "HDA SD7", };
5014 AssertCompile(RT_ELEMENTS(s_apszNames) == HDA_MAX_STREAMS);
5015 for (size_t i = 0; i < HDA_MAX_STREAMS; i++)
5016 {
5017 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hdaR3Timer, (void *)(uintptr_t)i,
5018 TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_RING0, s_apszNames[i], &pThis->aStreams[i].hTimer);
5019 AssertRCReturn(rc, rc);
5020
5021 rc = PDMDevHlpTimerSetCritSect(pDevIns, pThis->aStreams[i].hTimer, &pThis->CritSect);
5022 AssertRCReturn(rc, rc);
5023 }
5024
5025 /*
5026 * Create all hardware streams.
5027 */
5028 for (uint8_t i = 0; i < HDA_MAX_STREAMS; ++i)
5029 {
5030 rc = hdaR3StreamConstruct(&pThis->aStreams[i], &pThisCC->aStreams[i], pThis, pThisCC, i /* u8SD */);
5031 AssertRCReturn(rc, rc);
5032 }
5033
5034 hdaR3Reset(pDevIns);
5035
5036 /*
5037 * Info items and string formatter types. The latter is non-optional as
5038 * the info handles use (at least some of) the custom types and we cannot
5039 * accept screwing formatting.
5040 */
5041 PDMDevHlpDBGFInfoRegister(pDevIns, "hda", "HDA registers. (hda [register case-insensitive])", hdaR3DbgInfo);
5042 PDMDevHlpDBGFInfoRegister(pDevIns, "hdabdl",
5043 "HDA buffer descriptor list (BDL) and DMA stream positions. (hdabdl [stream number])",
5044 hdaR3DbgInfoBDL);
5045 PDMDevHlpDBGFInfoRegister(pDevIns, "hdastream", "HDA stream info. (hdastream [stream number])", hdaR3DbgInfoStream);
5046 PDMDevHlpDBGFInfoRegister(pDevIns, "hdcnodes", "HDA codec nodes.", hdaR3DbgInfoCodecNodes);
5047 PDMDevHlpDBGFInfoRegister(pDevIns, "hdcselector", "HDA codec's selector states [node number].", hdaR3DbgInfoCodecSelector);
5048 PDMDevHlpDBGFInfoRegister(pDevIns, "hdamixer", "HDA mixer state.", hdaR3DbgInfoMixer);
5049
5050 rc = RTStrFormatTypeRegister("sdctl", hdaR3StrFmtSDCTL, NULL);
5051 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5052 rc = RTStrFormatTypeRegister("sdsts", hdaR3StrFmtSDSTS, NULL);
5053 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5054 /** @todo the next two are rather pointless. */
5055 rc = RTStrFormatTypeRegister("sdfifos", hdaR3StrFmtSDFIFOS, NULL);
5056 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5057 rc = RTStrFormatTypeRegister("sdfifow", hdaR3StrFmtSDFIFOW, NULL);
5058 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5059
5060 /*
5061 * Asserting sanity.
5062 */
5063 AssertCompile(RT_ELEMENTS(pThis->au32Regs) < 256 /* assumption by HDAREGDESC::idxReg */);
5064 for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
5065 {
5066 struct HDAREGDESC const *pReg = &g_aHdaRegMap[i];
5067 struct HDAREGDESC const *pNextReg = i + 1 < RT_ELEMENTS(g_aHdaRegMap) ? &g_aHdaRegMap[i + 1] : NULL;
5068
5069 /* binary search order. */
5070 AssertReleaseMsg(!pNextReg || pReg->off + pReg->cb <= pNextReg->off,
5071 ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
5072 i, pReg->off, pReg->cb, i + 1, pNextReg->off, pNextReg->cb));
5073
5074 /* alignment. */
5075 AssertReleaseMsg( pReg->cb == 1
5076 || (pReg->cb == 2 && (pReg->off & 1) == 0)
5077 || (pReg->cb == 3 && (pReg->off & 3) == 0)
5078 || (pReg->cb == 4 && (pReg->off & 3) == 0),
5079 ("[%#x] = {%#x LB %#x}\n", i, pReg->off, pReg->cb));
5080
5081 /* registers are packed into dwords - with 3 exceptions with gaps at the end of the dword. */
5082 AssertRelease(((pReg->off + pReg->cb) & 3) == 0 || pNextReg);
5083 if (pReg->off & 3)
5084 {
5085 struct HDAREGDESC const *pPrevReg = i > 0 ? &g_aHdaRegMap[i - 1] : NULL;
5086 AssertReleaseMsg(pPrevReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->off, pReg->cb));
5087 if (pPrevReg)
5088 AssertReleaseMsg(pPrevReg->off + pPrevReg->cb == pReg->off,
5089 ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
5090 i - 1, pPrevReg->off, pPrevReg->cb, i + 1, pReg->off, pReg->cb));
5091 }
5092#if 0
5093 if ((pReg->offset + pReg->size) & 3)
5094 {
5095 AssertReleaseMsg(pNextReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
5096 if (pNextReg)
5097 AssertReleaseMsg(pReg->offset + pReg->size == pNextReg->offset,
5098 ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
5099 i, pReg->offset, pReg->size, i + 1, pNextReg->offset, pNextReg->size));
5100 }
5101#endif
5102 /* The final entry is a full DWORD, no gaps! Allows shortcuts. */
5103 AssertReleaseMsg(pNextReg || ((pReg->off + pReg->cb) & 3) == 0,
5104 ("[%#x] = {%#x LB %#x}\n", i, pReg->off, pReg->cb));
5105 }
5106
5107# ifdef VBOX_WITH_STATISTICS
5108 /*
5109 * Register statistics.
5110 */
5111 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn, STAMTYPE_PROFILE, "Input", STAMUNIT_TICKS_PER_CALL, "Profiling input.");
5112 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatOut, STAMTYPE_PROFILE, "Output", STAMUNIT_TICKS_PER_CALL, "Profiling output.");
5113 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, "BytesRead" , STAMUNIT_BYTES, "Bytes read (DMA) from the guest.");
5114 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "BytesWritten", STAMUNIT_BYTES, "Bytes written (DMA) to the guest.");
5115# ifdef VBOX_HDA_WITH_ON_REG_ACCESS_DMA
5116 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatAccessDmaOutput, STAMTYPE_COUNTER, "AccessDmaOutput", STAMUNIT_COUNT, "Number of on-register-access DMA sub-transfers we've made.");
5117 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatAccessDmaOutputToR3,STAMTYPE_COUNTER, "AccessDmaOutputToR3", STAMUNIT_COUNT, "Number of time the on-register-access DMA forced a ring-3 return.");
5118# endif
5119
5120 AssertCompile(RT_ELEMENTS(g_aHdaRegMap) == HDA_NUM_REGS);
5121 AssertCompile(RT_ELEMENTS(pThis->aStatRegReads) == HDA_NUM_REGS);
5122 AssertCompile(RT_ELEMENTS(pThis->aStatRegReadsToR3) == HDA_NUM_REGS);
5123 AssertCompile(RT_ELEMENTS(pThis->aStatRegWrites) == HDA_NUM_REGS);
5124 AssertCompile(RT_ELEMENTS(pThis->aStatRegWritesToR3) == HDA_NUM_REGS);
5125 for (size_t i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
5126 {
5127 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegReads[i], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
5128 g_aHdaRegMap[i].pszDesc, "Regs/%03x-%s-Reads", g_aHdaRegMap[i].off, g_aHdaRegMap[i].pszName);
5129 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegReadsToR3[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5130 g_aHdaRegMap[i].pszDesc, "Regs/%03x-%s-Reads-ToR3", g_aHdaRegMap[i].off, g_aHdaRegMap[i].pszName);
5131 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegWrites[i], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
5132 g_aHdaRegMap[i].pszDesc, "Regs/%03x-%s-Writes", g_aHdaRegMap[i].off, g_aHdaRegMap[i].pszName);
5133 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegWritesToR3[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5134 g_aHdaRegMap[i].pszDesc, "Regs/%03x-%s-Writes-ToR3", g_aHdaRegMap[i].off, g_aHdaRegMap[i].pszName);
5135 }
5136 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiReadsR3, STAMTYPE_COUNTER, "RegMultiReadsR3", STAMUNIT_OCCURENCES, "Register read not targeting just one register, handled in ring-3");
5137 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiReadsRZ, STAMTYPE_COUNTER, "RegMultiReadsRZ", STAMUNIT_OCCURENCES, "Register read not targeting just one register, handled in ring-0");
5138 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiWritesR3, STAMTYPE_COUNTER, "RegMultiWritesR3", STAMUNIT_OCCURENCES, "Register writes not targeting just one register, handled in ring-3");
5139 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiWritesRZ, STAMTYPE_COUNTER, "RegMultiWritesRZ", STAMUNIT_OCCURENCES, "Register writes not targeting just one register, handled in ring-0");
5140 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegSubWriteR3, STAMTYPE_COUNTER, "RegSubWritesR3", STAMUNIT_OCCURENCES, "Trucated register writes, handled in ring-3");
5141 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegSubWriteRZ, STAMTYPE_COUNTER, "RegSubWritesRZ", STAMUNIT_OCCURENCES, "Trucated register writes, handled in ring-0");
5142 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegUnknownReads, STAMTYPE_COUNTER, "RegUnknownReads", STAMUNIT_OCCURENCES, "Reads of unknown registers.");
5143 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegUnknownWrites, STAMTYPE_COUNTER, "RegUnknownWrites", STAMUNIT_OCCURENCES, "Writes to unknown registers.");
5144 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegWritesBlockedByReset, STAMTYPE_COUNTER, "RegWritesBlockedByReset", STAMUNIT_OCCURENCES, "Writes blocked by pending reset (GCTL/CRST)");
5145 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegWritesBlockedByRun, STAMTYPE_COUNTER, "RegWritesBlockedByRun", STAMUNIT_OCCURENCES, "Writes blocked by byte RUN bit.");
5146# endif
5147
5148 for (uint8_t idxStream = 0; idxStream < RT_ELEMENTS(pThisCC->aStreams); idxStream++)
5149 {
5150 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowProblems, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5151 "Number of internal DMA buffer problems.", "Stream%u/DMABufferProblems", idxStream);
5152 if (hdaGetDirFromSD(idxStream) == PDMAUDIODIR_OUT)
5153 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5154 "Number of internal DMA buffer overflows.", "Stream%u/DMABufferOverflows", idxStream);
5155 else
5156 {
5157 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5158 "Number of internal DMA buffer underuns.", "Stream%u/DMABufferUnderruns", idxStream);
5159 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrorBytes, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5160 "Number of bytes of silence added to cope with underruns.", "Stream%u/DMABufferSilence", idxStream);
5161 }
5162 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaSkippedPendingBcis, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5163 "DMA transfer period skipped because of BCIS pending.", "Stream%u/DMASkippedPendingBCIS", idxStream);
5164
5165 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.offRead, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5166 "Virtual internal buffer read position.", "Stream%u/offRead", idxStream);
5167 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.offWrite, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5168 "Virtual internal buffer write position.", "Stream%u/offWrite", idxStream);
5169 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.cbCurDmaPeriod, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5170 "Bytes transfered per DMA timer callout.", "Stream%u/cbCurDmaPeriod", idxStream);
5171 PDMDevHlpSTAMRegisterF(pDevIns, (void*)&pThis->aStreams[idxStream].State.fRunning, STAMTYPE_BOOL, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5172 "True if the stream is in RUN mode.", "Stream%u/fRunning", idxStream);
5173 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.uHz, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_HZ,
5174 "The stream frequency.", "Stream%u/Cfg/Hz", idxStream);
5175 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cbFrame, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5176 "The frame size.", "Stream%u/Cfg/FrameSize", idxStream);
5177#if 0 /** @todo this would require some callback or expansion. */
5178 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cChannelsX, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5179 "The number of channels.", "Stream%u/Cfg/Channels-Host", idxStream);
5180 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.Mapping.GuestProps.cChannels, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5181 "The number of channels.", "Stream%u/Cfg/Channels-Guest", idxStream);
5182 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cbSample, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5183 "The size of a sample (per channel).", "Stream%u/Cfg/cbSample", idxStream);
5184#endif
5185
5186 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaBufSize, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5187 "Size of the internal DMA buffer.", "Stream%u/DMABufSize", idxStream);
5188 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaBufUsed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5189 "Number of bytes used in the internal DMA buffer.", "Stream%u/DMABufUsed", idxStream);
5190
5191 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatStart, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
5192 "Starting the stream.", "Stream%u/Start", idxStream);
5193 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatStop, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
5194 "Stopping the stream.", "Stream%u/Stop", idxStream);
5195 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatReset, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
5196 "Resetting the stream.", "Stream%u/Reset", idxStream);
5197 }
5198
5199 return VINF_SUCCESS;
5200}
5201
5202#else /* !IN_RING3 */
5203
5204/**
5205 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
5206 */
5207static DECLCALLBACK(int) hdaRZConstruct(PPDMDEVINS pDevIns)
5208{
5209 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* this shall come first */
5210 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
5211 PHDASTATER0 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER0);
5212
5213 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
5214 AssertRCReturn(rc, rc);
5215
5216 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, hdaMmioWrite, hdaMmioRead, NULL /*pvUser*/);
5217 AssertRCReturn(rc, rc);
5218
5219# if 0 /* Codec is not yet kosher enough for ring-0. @bugref{9890c64} */
5220 /* Construct the R0 codec part. */
5221 rc = hdaR0CodecConstruct(pDevIns, &pThis->Codec, &pThisCC->Codec);
5222 AssertRCReturn(rc, rc);
5223# else
5224 RT_NOREF(pThisCC);
5225# endif
5226
5227 return VINF_SUCCESS;
5228}
5229
5230#endif /* !IN_RING3 */
5231
5232/**
5233 * The device registration structure.
5234 */
5235const PDMDEVREG g_DeviceHDA =
5236{
5237 /* .u32Version = */ PDM_DEVREG_VERSION,
5238 /* .uReserved0 = */ 0,
5239 /* .szName = */ "hda",
5240 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
5241 | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION /* stream clearnup with working drivers */,
5242 /* .fClass = */ PDM_DEVREG_CLASS_AUDIO,
5243 /* .cMaxInstances = */ 1,
5244 /* .uSharedVersion = */ 42,
5245 /* .cbInstanceShared = */ sizeof(HDASTATE),
5246 /* .cbInstanceCC = */ CTX_EXPR(sizeof(HDASTATER3), sizeof(HDASTATER0), 0),
5247 /* .cbInstanceRC = */ 0,
5248 /* .cMaxPciDevices = */ 1,
5249 /* .cMaxMsixVectors = */ 0,
5250 /* .pszDescription = */ "Intel HD Audio Controller",
5251#if defined(IN_RING3)
5252 /* .pszRCMod = */ "VBoxDDRC.rc",
5253 /* .pszR0Mod = */ "VBoxDDR0.r0",
5254 /* .pfnConstruct = */ hdaR3Construct,
5255 /* .pfnDestruct = */ hdaR3Destruct,
5256 /* .pfnRelocate = */ NULL,
5257 /* .pfnMemSetup = */ NULL,
5258 /* .pfnPowerOn = */ NULL,
5259 /* .pfnReset = */ hdaR3Reset,
5260 /* .pfnSuspend = */ NULL,
5261 /* .pfnResume = */ NULL,
5262 /* .pfnAttach = */ hdaR3Attach,
5263 /* .pfnDetach = */ hdaR3Detach,
5264 /* .pfnQueryInterface = */ NULL,
5265 /* .pfnInitComplete = */ NULL,
5266 /* .pfnPowerOff = */ hdaR3PowerOff,
5267 /* .pfnSoftReset = */ NULL,
5268 /* .pfnReserved0 = */ NULL,
5269 /* .pfnReserved1 = */ NULL,
5270 /* .pfnReserved2 = */ NULL,
5271 /* .pfnReserved3 = */ NULL,
5272 /* .pfnReserved4 = */ NULL,
5273 /* .pfnReserved5 = */ NULL,
5274 /* .pfnReserved6 = */ NULL,
5275 /* .pfnReserved7 = */ NULL,
5276#elif defined(IN_RING0)
5277 /* .pfnEarlyConstruct = */ NULL,
5278 /* .pfnConstruct = */ hdaRZConstruct,
5279 /* .pfnDestruct = */ NULL,
5280 /* .pfnFinalDestruct = */ NULL,
5281 /* .pfnRequest = */ NULL,
5282 /* .pfnReserved0 = */ NULL,
5283 /* .pfnReserved1 = */ NULL,
5284 /* .pfnReserved2 = */ NULL,
5285 /* .pfnReserved3 = */ NULL,
5286 /* .pfnReserved4 = */ NULL,
5287 /* .pfnReserved5 = */ NULL,
5288 /* .pfnReserved6 = */ NULL,
5289 /* .pfnReserved7 = */ NULL,
5290#elif defined(IN_RC)
5291 /* .pfnConstruct = */ hdaRZConstruct,
5292 /* .pfnReserved0 = */ NULL,
5293 /* .pfnReserved1 = */ NULL,
5294 /* .pfnReserved2 = */ NULL,
5295 /* .pfnReserved3 = */ NULL,
5296 /* .pfnReserved4 = */ NULL,
5297 /* .pfnReserved5 = */ NULL,
5298 /* .pfnReserved6 = */ NULL,
5299 /* .pfnReserved7 = */ NULL,
5300#else
5301# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5302#endif
5303 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
5304};
5305
5306#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
5307
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