VirtualBox

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

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

DevHda: Made the register map local to DevHda.cpp only, DevHdaStream.cpp does not need it. bugref:9890

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