VirtualBox

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

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

DevHda: Reordered HDAREGDESC so we avoid alignment padding. Saves ~900 bytes. bugref:9890

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