VirtualBox

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

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

DevHda: Optimize HDAREGDESC a little more by reducing the size, fFlags and mem_idx members to uint8_t. bugref:9890

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