VirtualBox

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

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

DevHda: Added removal todo on InitialDelayMs (it's too involved to do it now). bugref:9890

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