VirtualBox

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

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

DevHda: Added the minimum of registers linux accesses for the 8086:9d70 device. The result sounds pretty decent, maybe luck or maybe because of SDnDPIB registers used for getting stream position. Recording not tested. bugref:9890

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