VirtualBox

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

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

Audio: Some info item fixes and docs updates. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 212.2 KB
Line 
1/* $Id: DevHda.cpp 89821 2021-06-21 13:04:40Z 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, PCPDMAUDIOSTREAMCFG 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, PCPDMAUDIOSTREAMCFG 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 LogFunc(("[LUN#%RU8] %s\n", pDrv->uLUN, pCfg->szName));
2308
2309 AssertPtr(pDrvStream);
2310 AssertMsg(pDrvStream->pMixStrm == NULL, ("[LUN#%RU8] Driver stream already present when it must not\n", pDrv->uLUN));
2311
2312 PAUDMIXSTREAM pMixStrm = NULL;
2313 int rc = AudioMixerSinkCreateStream(pMixSink, pDrv->pConnector, pCfg, pDevIns, &pMixStrm);
2314 LogFlowFunc(("LUN#%RU8: Created stream \"%s\" for sink, rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc));
2315 if (RT_SUCCESS(rc))
2316 {
2317 rc = AudioMixerSinkAddStream(pMixSink, pMixStrm);
2318 LogFlowFunc(("LUN#%RU8: Added stream \"%s\" to sink, rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc));
2319 if (RT_FAILURE(rc))
2320 AudioMixerStreamDestroy(pMixStrm, pDevIns, true /*fImmediate*/);
2321 }
2322
2323 if (RT_SUCCESS(rc))
2324 pDrvStream->pMixStrm = pMixStrm;
2325
2326 LogFlowFuncLeaveRC(rc);
2327 return rc;
2328}
2329
2330/**
2331 * Adds all current driver streams to a specific mixer sink.
2332 *
2333 * @returns VBox status code.
2334 * @param pDevIns The HDA device instance.
2335 * @param pThisCC The ring-3 HDA device state.
2336 * @param pMixSink Audio mixer sink to add stream to.
2337 * @param pCfg Audio stream configuration to use for the audio streams
2338 * to add.
2339 */
2340static int hdaR3MixerAddDrvStreams(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PAUDMIXSINK pMixSink, PCPDMAUDIOSTREAMCFG pCfg)
2341{
2342 AssertPtrReturn(pMixSink, VERR_INVALID_POINTER);
2343 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2344
2345 LogFunc(("Sink=%s, Stream=%s\n", pMixSink->pszName, pCfg->szName));
2346
2347 int rc;
2348 if (AudioHlpStreamCfgIsValid(pCfg))
2349 {
2350 rc = AudioMixerSinkSetFormat(pMixSink, &pCfg->Props, pCfg->Device.cMsSchedulingHint);
2351 if (RT_SUCCESS(rc))
2352 {
2353 PHDADRIVER pDrv;
2354 RTListForEach(&pThisCC->lstDrv, pDrv, HDADRIVER, Node)
2355 {
2356 /* We ignore failures here because one non-working driver shouldn't
2357 be allowed to spoil it for everyone else. */
2358 int rc2 = hdaR3MixerAddDrvStream(pDevIns, pMixSink, pCfg, pDrv);
2359 if (RT_FAILURE(rc2))
2360 LogFunc(("Attaching stream failed with %Rrc (ignored)\n", rc2));
2361 }
2362 }
2363 }
2364 else
2365 rc = VERR_INVALID_PARAMETER;
2366 return rc;
2367}
2368
2369/**
2370 * @interface_method_impl{HDACODECR3,pfnCbMixerAddStream}
2371 */
2372static DECLCALLBACK(int) hdaR3MixerAddStream(PPDMDEVINS pDevIns, PDMAUDIOMIXERCTL enmMixerCtl, PCPDMAUDIOSTREAMCFG pCfg)
2373{
2374 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
2375 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2376
2377 int rc;
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 fMuted=%RTbool auChannels=%.*Rhxs\n",
2588 pSink->pMixSink->pszName, pVol->fMuted, sizeof(pVol->auChannels), pVol->auChannels));
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 char szTmp[PDMAUDIOSTRMCFGTOSTRING_MAX];
4123 PHDASTREAM const pStream = &pThis->aStreams[idxStream];
4124 pHlp->pfnPrintf(pHlp, "Stream #%d: %s\n", idxStream, PDMAudioStrmCfgToString(&pStream->State.Cfg, szTmp, sizeof(szTmp)));
4125 pHlp->pfnPrintf(pHlp, " SD%dCTL : %R[sdctl]\n", idxStream, HDA_STREAM_REG(pThis, CTL, idxStream));
4126 pHlp->pfnPrintf(pHlp, " SD%dCTS : %R[sdsts]\n", idxStream, HDA_STREAM_REG(pThis, STS, idxStream));
4127 pHlp->pfnPrintf(pHlp, " SD%dFIFOS: %R[sdfifos]\n", idxStream, HDA_STREAM_REG(pThis, FIFOS, idxStream));
4128 pHlp->pfnPrintf(pHlp, " SD%dFIFOW: %R[sdfifow]\n", idxStream, HDA_STREAM_REG(pThis, FIFOW, idxStream));
4129 pHlp->pfnPrintf(pHlp, " Current BDLE%02u: %s%#RX64 LB %#x%s - off=%#x\n", pStream->State.idxCurBdle, "%%" /*vboxdbg phys prefix*/,
4130 pStream->State.aBdl[pStream->State.idxCurBdle].GCPhys, pStream->State.aBdl[pStream->State.idxCurBdle].cb,
4131 pStream->State.aBdl[pStream->State.idxCurBdle].fFlags ? " IOC" : "", pStream->State.offCurBdle);
4132}
4133
4134/** Worker for hdaR3DbgInfoBDL. */
4135static void hdaR3DbgPrintBDL(PPDMDEVINS pDevIns, PHDASTATE pThis, PCDBGFINFOHLP pHlp, int idxStream)
4136{
4137 const PHDASTREAM pStream = &pThis->aStreams[idxStream];
4138 PCPDMAUDIOPCMPROPS pGuestProps = &pStream->State.Cfg.Props; /** @todo We don't make a distinction any more. The mixer hides that now. */
4139
4140 uint64_t const u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, idxStream),
4141 HDA_STREAM_REG(pThis, BDPU, idxStream));
4142 uint16_t const u16LVI = HDA_STREAM_REG(pThis, LVI, idxStream);
4143 uint32_t const u32CBL = HDA_STREAM_REG(pThis, CBL, idxStream);
4144 uint8_t const idxCurBdle = pStream->State.idxCurBdle;
4145 pHlp->pfnPrintf(pHlp, "Stream #%d BDL: %s%#011RX64 LB %#x (LVI=%u)\n", idxStream, "%%" /*vboxdbg phys prefix*/,
4146 u64BaseDMA, u16LVI * sizeof(HDABDLEDESC), u16LVI);
4147 if (u64BaseDMA || idxCurBdle != 0 || pStream->State.aBdl[idxCurBdle].GCPhys != 0 || pStream->State.aBdl[idxCurBdle].cb != 0)
4148 pHlp->pfnPrintf(pHlp, " Current: BDLE%03u: %s%#011RX64 LB %#x%s - off=%#x LPIB=%#RX32\n",
4149 pStream->State.idxCurBdle, "%%" /*vboxdbg phys prefix*/,
4150 pStream->State.aBdl[idxCurBdle].GCPhys, pStream->State.aBdl[idxCurBdle].cb,
4151 pStream->State.aBdl[idxCurBdle].fFlags ? " IOC" : "", pStream->State.offCurBdle,
4152 HDA_STREAM_REG(pThis, LPIB, idxStream));
4153 if (!u64BaseDMA)
4154 return;
4155
4156 /*
4157 * The BDL:
4158 */
4159 uint64_t cbTotal = 0;
4160 for (uint16_t i = 0; i < u16LVI + 1; i++)
4161 {
4162 HDABDLEDESC bd = {0, 0, 0};
4163 PDMDevHlpPCIPhysRead(pDevIns, u64BaseDMA + i * sizeof(HDABDLEDESC), &bd, sizeof(bd));
4164
4165 char szFlags[64];
4166 szFlags[0] = '\0';
4167 if (bd.fFlags & ~HDA_BDLE_F_IOC)
4168 RTStrPrintf(szFlags, sizeof(szFlags), " !!fFlags=%#x!!\n", bd.fFlags);
4169 pHlp->pfnPrintf(pHlp, " %sBDLE%03u: %s%#011RX64 LB %#06x (%RU64 us) %s%s\n", idxCurBdle == i ? "=>" : " ", i, "%%",
4170 bd.u64BufAddr, bd.u32BufSize, PDMAudioPropsBytesToMicro(pGuestProps, bd.u32BufSize),
4171 bd.fFlags & HDA_BDLE_F_IOC ? " IOC=1" : "", szFlags);
4172
4173 if (memcmp(&bd, &pStream->State.aBdl[i], sizeof(bd)) != 0)
4174 {
4175 szFlags[0] = '\0';
4176 if (bd.fFlags & ~HDA_BDLE_F_IOC)
4177 RTStrPrintf(szFlags, sizeof(szFlags), " !!fFlags=%#x!!\n", bd.fFlags);
4178 pHlp->pfnPrintf(pHlp, " !!!loaded: %s%#011RX64 LB %#06x %s%s\n", "%%", pStream->State.aBdl[i].GCPhys,
4179 pStream->State.aBdl[i].cb, pStream->State.aBdl[i].fFlags & HDA_BDLE_F_IOC ? " IOC=1" : "", szFlags);
4180 }
4181
4182 cbTotal += bd.u32BufSize;
4183 }
4184 pHlp->pfnPrintf(pHlp, " Total: %#RX64 bytes (%RU64), %RU64 ms\n", cbTotal, cbTotal,
4185 PDMAudioPropsBytesToMilli(pGuestProps, (uint32_t)cbTotal));
4186 if (cbTotal != u32CBL)
4187 pHlp->pfnPrintf(pHlp, " Warning: %#RX64 bytes does not match CBL (%#RX64)!\n", cbTotal, u32CBL);
4188
4189 /*
4190 * The scheduling plan.
4191 */
4192 uint16_t const idxSchedule = pStream->State.idxSchedule;
4193 pHlp->pfnPrintf(pHlp, " Scheduling: %u items, %u prologue. Current: %u, loop %u.\n", pStream->State.cSchedule,
4194 pStream->State.cSchedulePrologue, idxSchedule, pStream->State.idxScheduleLoop);
4195 for (uint16_t i = 0; i < pStream->State.cSchedule; i++)
4196 pHlp->pfnPrintf(pHlp, " %s#%02u: %#x bytes, %u loop%s, %RU32 ticks. BDLE%u thru BDLE%u\n",
4197 i == idxSchedule ? "=>" : " ", i,
4198 pStream->State.aSchedule[i].cbPeriod, pStream->State.aSchedule[i].cLoops,
4199 pStream->State.aSchedule[i].cLoops == 1 ? "" : "s",
4200 pStream->State.aSchedule[i].cPeriodTicks, pStream->State.aSchedule[i].idxFirst,
4201 pStream->State.aSchedule[i].idxFirst + pStream->State.aSchedule[i].cEntries - 1);
4202}
4203
4204/** Used by hdaR3DbgInfoStream and hdaR3DbgInfoBDL. */
4205static int hdaR3DbgLookupStrmIdx(PCDBGFINFOHLP pHlp, const char *pszArgs)
4206{
4207 if (pszArgs && *pszArgs)
4208 {
4209 int32_t idxStream;
4210 int rc = RTStrToInt32Full(pszArgs, 0, &idxStream);
4211 if (RT_SUCCESS(rc) && idxStream >= -1 && idxStream < HDA_MAX_STREAMS)
4212 return idxStream;
4213 pHlp->pfnPrintf(pHlp, "Argument '%s' is not a valid stream number!\n", pszArgs);
4214 }
4215 return -1;
4216}
4217
4218/**
4219 * @callback_method_impl{FNDBGFHANDLERDEV, hdastream}
4220 */
4221static DECLCALLBACK(void) hdaR3DbgInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4222{
4223 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4224 int idxStream = hdaR3DbgLookupStrmIdx(pHlp, pszArgs);
4225 if (idxStream != -1)
4226 hdaR3DbgPrintStream(pThis, pHlp, idxStream);
4227 else
4228 for (idxStream = 0; idxStream < HDA_MAX_STREAMS; ++idxStream)
4229 hdaR3DbgPrintStream(pThis, pHlp, idxStream);
4230}
4231
4232/**
4233 * @callback_method_impl{FNDBGFHANDLERDEV, hdabdl}
4234 */
4235static DECLCALLBACK(void) hdaR3DbgInfoBDL(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4236{
4237 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4238 int idxStream = hdaR3DbgLookupStrmIdx(pHlp, pszArgs);
4239 if (idxStream != -1)
4240 hdaR3DbgPrintBDL(pDevIns, pThis, pHlp, idxStream);
4241 else
4242 {
4243 for (idxStream = 0; idxStream < HDA_MAX_STREAMS; ++idxStream)
4244 hdaR3DbgPrintBDL(pDevIns, pThis, pHlp, idxStream);
4245 idxStream = -1;
4246 }
4247
4248 /*
4249 * DMA stream positions:
4250 */
4251 uint64_t const uDPBase = pThis->u64DPBase & DPBASE_ADDR_MASK;
4252 pHlp->pfnPrintf(pHlp, "DMA counters %#011RX64 LB %#x, %s:\n", uDPBase, HDA_MAX_STREAMS * 2 * sizeof(uint32_t),
4253 pThis->fDMAPosition ? "enabled" : "disabled");
4254 if (uDPBase)
4255 {
4256 struct
4257 {
4258 uint32_t off, uReserved;
4259 } aPositions[HDA_MAX_STREAMS];
4260 RT_ZERO(aPositions);
4261 PDMDevHlpPCIPhysRead(pDevIns, uDPBase , &aPositions[0], sizeof(aPositions));
4262
4263 for (unsigned i = 0; i < RT_ELEMENTS(aPositions); i++)
4264 if (idxStream == -1 || i == (unsigned)idxStream) /* lazy bird */
4265 {
4266 char szReserved[64];
4267 szReserved[0] = '\0';
4268 if (aPositions[i].uReserved != 0)
4269 RTStrPrintf(szReserved, sizeof(szReserved), " reserved=%#x", aPositions[i].uReserved);
4270 pHlp->pfnPrintf(pHlp, " Stream #%u DMA @ %#x%s\n", i, aPositions[i].off, szReserved);
4271 }
4272 }
4273}
4274
4275/**
4276 * @callback_method_impl{FNDBGFHANDLERDEV, hdcnodes}
4277 */
4278static DECLCALLBACK(void) hdaR3DbgInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4279{
4280 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4281 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4282
4283 if (pThisCC->pCodec->pfnDbgListNodes)
4284 pThisCC->pCodec->pfnDbgListNodes(&pThis->Codec, pThisCC->pCodec, pHlp, pszArgs);
4285 else
4286 pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
4287}
4288
4289/**
4290 * @callback_method_impl{FNDBGFHANDLERDEV, hdcselector}
4291 */
4292static DECLCALLBACK(void) hdaR3DbgInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4293{
4294 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4295 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4296
4297 if (pThisCC->pCodec->pfnDbgSelector)
4298 pThisCC->pCodec->pfnDbgSelector(&pThis->Codec, pThisCC->pCodec, pHlp, pszArgs);
4299 else
4300 pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
4301}
4302
4303/**
4304 * @callback_method_impl{FNDBGFHANDLERDEV, hdamixer}
4305 */
4306static DECLCALLBACK(void) hdaR3DbgInfoMixer(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4307{
4308 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4309
4310 if (pThisCC->pMixer)
4311 AudioMixerDebug(pThisCC->pMixer, pHlp, pszArgs);
4312 else
4313 pHlp->pfnPrintf(pHlp, "Mixer not available\n");
4314}
4315
4316
4317/*********************************************************************************************************************************
4318* PDMIBASE *
4319*********************************************************************************************************************************/
4320
4321/**
4322 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4323 */
4324static DECLCALLBACK(void *) hdaR3QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
4325{
4326 PHDASTATER3 pThisCC = RT_FROM_MEMBER(pInterface, HDASTATER3, IBase);
4327
4328 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
4329 return NULL;
4330}
4331
4332
4333/*********************************************************************************************************************************
4334* PDMDEVREGR3 *
4335*********************************************************************************************************************************/
4336
4337/**
4338 * Worker for hdaR3Construct() and hdaR3Attach().
4339 *
4340 * @returns VBox status code.
4341 * @param pDevIns The device instance.
4342 * @param pThis The shared HDA device state.
4343 * @param pThisCC The ring-3 HDA device state.
4344 * @param uLUN The logical unit which is being detached.
4345 * @param ppDrv Attached driver instance on success. Optional.
4346 */
4347static int hdaR3AttachInternal(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, unsigned uLUN, PHDADRIVER *ppDrv)
4348{
4349 /*
4350 * Attach driver.
4351 */
4352 char *pszDesc = RTStrAPrintf2("Audio driver port (HDA) for LUN#%u", uLUN);
4353 AssertLogRelReturn(pszDesc, VERR_NO_STR_MEMORY);
4354
4355 PPDMIBASE pDrvBase;
4356 int rc = PDMDevHlpDriverAttach(pDevIns, uLUN, &pThisCC->IBase, &pDrvBase, pszDesc);
4357 if (RT_SUCCESS(rc))
4358 {
4359 PHDADRIVER pDrv = (PHDADRIVER)RTMemAllocZ(sizeof(HDADRIVER));
4360 if (pDrv)
4361 {
4362 pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
4363 AssertPtr(pDrv->pConnector);
4364 if (RT_VALID_PTR(pDrv->pConnector))
4365 {
4366 pDrv->pDrvBase = pDrvBase;
4367 pDrv->pHDAStateShared = pThis;
4368 pDrv->pHDAStateR3 = pThisCC;
4369 pDrv->uLUN = uLUN;
4370
4371 /* Attach to driver list if not attached yet. */
4372 if (!pDrv->fAttached)
4373 {
4374 RTListAppend(&pThisCC->lstDrv, &pDrv->Node);
4375 pDrv->fAttached = true;
4376 }
4377
4378 if (ppDrv)
4379 *ppDrv = pDrv;
4380
4381 /*
4382 * While we're here, give the windows backends a hint about our typical playback
4383 * configuration.
4384 * Note! If 48000Hz is advertised to the guest, add it here.
4385 */
4386 if ( pDrv->pConnector
4387 && pDrv->pConnector->pfnStreamConfigHint)
4388 {
4389 PDMAUDIOSTREAMCFG Cfg;
4390 RT_ZERO(Cfg);
4391 Cfg.enmDir = PDMAUDIODIR_OUT;
4392 Cfg.enmPath = PDMAUDIOPATH_OUT_FRONT;
4393 Cfg.Device.cMsSchedulingHint = 10;
4394 Cfg.Backend.cFramesPreBuffering = UINT32_MAX;
4395 PDMAudioPropsInit(&Cfg.Props, 2, true /*fSigned*/, 2, 44100);
4396 RTStrPrintf(Cfg.szName, sizeof(Cfg.szName), "output 44.1kHz 2ch S16 (HDA config hint)");
4397
4398 pDrv->pConnector->pfnStreamConfigHint(pDrv->pConnector, &Cfg); /* (may trash CfgReq) */
4399 }
4400
4401 LogFunc(("LUN#%u: returns VINF_SUCCESS (pCon=%p)\n", uLUN, pDrv->pConnector));
4402 return VINF_SUCCESS;
4403 }
4404
4405 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
4406 }
4407 else
4408 rc = VERR_NO_MEMORY;
4409 }
4410 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4411 LogFunc(("No attached driver for LUN #%u\n", uLUN));
4412 else
4413 LogFunc(("Failed attaching driver for LUN #%u: %Rrc\n", uLUN, rc));
4414
4415 RTStrFree(pszDesc);
4416 LogFunc(("LUN#%u: rc=%Rrc\n", uLUN, rc));
4417 return rc;
4418}
4419
4420
4421/**
4422 * @interface_method_impl{PDMDEVREG,pfnAttach}
4423 */
4424static DECLCALLBACK(int) hdaR3Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
4425{
4426 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4427 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4428 RT_NOREF(fFlags);
4429 LogFunc(("uLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
4430
4431 DEVHDA_LOCK_RETURN(pDevIns, pThis, VERR_IGNORED);
4432
4433 PHDADRIVER pDrv;
4434 int rc = hdaR3AttachInternal(pDevIns, pThis, pThisCC, uLUN, &pDrv);
4435 if (RT_SUCCESS(rc))
4436 {
4437 int rc2 = hdaR3MixerAddDrv(pDevIns, pThisCC, pDrv);
4438 if (RT_FAILURE(rc2))
4439 LogFunc(("hdaR3MixerAddDrv failed with %Rrc (ignored)\n", rc2));
4440 }
4441
4442 DEVHDA_UNLOCK(pDevIns, pThis);
4443 return rc;
4444}
4445
4446
4447/**
4448 * Worker for hdaR3Detach that does all but free pDrv.
4449 *
4450 * This is called to let the device detach from a driver for a specified LUN
4451 * at runtime.
4452 *
4453 * @param pDevIns The device instance.
4454 * @param pThisCC The ring-3 HDA device state.
4455 * @param pDrv Driver to detach from device.
4456 */
4457static void hdaR3DetachInternal(PPDMDEVINS pDevIns, PHDASTATER3 pThisCC, PHDADRIVER pDrv)
4458{
4459 /* Remove the driver from our list and destory it's associated streams.
4460 This also will un-set the driver as a recording source (if associated). */
4461 hdaR3MixerRemoveDrv(pDevIns, pThisCC, pDrv);
4462 LogFunc(("LUN#%u detached\n", pDrv->uLUN));
4463}
4464
4465
4466/**
4467 * @interface_method_impl{PDMDEVREG,pfnDetach}
4468 */
4469static DECLCALLBACK(void) hdaR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4470{
4471 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4472 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4473 RT_NOREF(fFlags);
4474 LogFunc(("iLUN=%u, fFlags=%#x\n", iLUN, fFlags));
4475
4476 DEVHDA_LOCK(pDevIns, pThis);
4477
4478 PHDADRIVER pDrv;
4479 RTListForEach(&pThisCC->lstDrv, pDrv, HDADRIVER, Node)
4480 {
4481 if (pDrv->uLUN == iLUN)
4482 {
4483 hdaR3DetachInternal(pDevIns, pThisCC, pDrv);
4484 RTMemFree(pDrv);
4485 DEVHDA_UNLOCK(pDevIns, pThis);
4486 return;
4487 }
4488 }
4489
4490 DEVHDA_UNLOCK(pDevIns, pThis);
4491 LogFunc(("LUN#%u was not found\n", iLUN));
4492}
4493
4494
4495/**
4496 * Powers off the device.
4497 *
4498 * @param pDevIns Device instance to power off.
4499 */
4500static DECLCALLBACK(void) hdaR3PowerOff(PPDMDEVINS pDevIns)
4501{
4502 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4503 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4504
4505 DEVHDA_LOCK_RETURN_VOID(pDevIns, pThis);
4506
4507 LogRel2(("HDA: Powering off ...\n"));
4508
4509/** @todo r=bird: What this "releasing references" and whatever here is
4510 * referring to, is apparently that the device is destroyed after the
4511 * drivers, so creating trouble as those structures have been torn down
4512 * already... Reverse order, like we do for power off? Need a new
4513 * PDMDEVREG flag. */
4514
4515 /* Ditto goes for the codec, which in turn uses the mixer. */
4516 hdaR3CodecPowerOff(pThisCC->pCodec);
4517
4518 /* This is to prevent us from calling into the mixer and mixer sink code
4519 after it has been destroyed below. */
4520 for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
4521 pThisCC->aStreams[i].State.pAioRegSink = NULL; /* don't need to remove, we're destorying it. */
4522
4523 /*
4524 * Note: Destroy the mixer while powering off and *not* in hdaR3Destruct,
4525 * giving the mixer the chance to release any references held to
4526 * PDM audio streams it maintains.
4527 */
4528 if (pThisCC->pMixer)
4529 {
4530 AudioMixerDestroy(pThisCC->pMixer, pDevIns);
4531 pThisCC->pMixer = NULL;
4532 }
4533
4534 DEVHDA_UNLOCK(pDevIns, pThis);
4535}
4536
4537
4538/**
4539 * @interface_method_impl{PDMDEVREG,pfnReset}
4540 */
4541static DECLCALLBACK(void) hdaR3Reset(PPDMDEVINS pDevIns)
4542{
4543 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4544 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4545
4546 LogFlowFuncEnter();
4547
4548 DEVHDA_LOCK_RETURN_VOID(pDevIns, pThis);
4549
4550 /*
4551 * 18.2.6,7 defines that values of this registers might be cleared on power on/reset
4552 * hdaR3Reset shouldn't affects these registers.
4553 */
4554 HDA_REG(pThis, WAKEEN) = 0x0;
4555
4556 hdaR3GCTLReset(pDevIns, pThis, pThisCC);
4557
4558 /* Indicate that HDA is not in reset. The firmware is supposed to (un)reset HDA,
4559 * but we can take a shortcut.
4560 */
4561 HDA_REG(pThis, GCTL) = HDA_GCTL_CRST;
4562
4563 DEVHDA_UNLOCK(pDevIns, pThis);
4564}
4565
4566
4567/**
4568 * @interface_method_impl{PDMDEVREG,pfnDestruct}
4569 */
4570static DECLCALLBACK(int) hdaR3Destruct(PPDMDEVINS pDevIns)
4571{
4572 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); /* this shall come first */
4573 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4574 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4575 DEVHDA_LOCK(pDevIns, pThis); /** @todo r=bird: this will fail on early constructor failure. */
4576
4577 PHDADRIVER pDrv;
4578 while (!RTListIsEmpty(&pThisCC->lstDrv))
4579 {
4580 pDrv = RTListGetFirst(&pThisCC->lstDrv, HDADRIVER, Node);
4581
4582 RTListNodeRemove(&pDrv->Node);
4583 RTMemFree(pDrv);
4584 }
4585
4586 if (pThisCC->pCodec)
4587 {
4588 RTMemFree(pThisCC->pCodec);
4589 pThisCC->pCodec = NULL;
4590 }
4591
4592 hdaCodecDestruct(&pThis->Codec);
4593
4594 for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
4595 hdaR3StreamDestroy(&pThis->aStreams[i], &pThisCC->aStreams[i]);
4596
4597 /* We don't always go via PowerOff, so make sure the mixer is destroyed. */
4598 if (pThisCC->pMixer)
4599 {
4600 AudioMixerDestroy(pThisCC->pMixer, pDevIns);
4601 pThisCC->pMixer = NULL;
4602 }
4603
4604 DEVHDA_UNLOCK(pDevIns, pThis);
4605 return VINF_SUCCESS;
4606}
4607
4608
4609/**
4610 * @interface_method_impl{PDMDEVREG,pfnConstruct}
4611 */
4612static DECLCALLBACK(int) hdaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
4613{
4614 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* this shall come first */
4615 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4616 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4617 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4618 Assert(iInstance == 0); RT_NOREF(iInstance);
4619
4620 /*
4621 * Initialize the state sufficently to make the destructor work.
4622 */
4623 pThis->uAlignmentCheckMagic = HDASTATE_ALIGNMENT_CHECK_MAGIC;
4624 RTListInit(&pThisCC->lstDrv);
4625 pThis->cbCorbBuf = HDA_CORB_SIZE * HDA_CORB_ELEMENT_SIZE;
4626 pThis->cbRirbBuf = HDA_RIRB_SIZE * HDA_RIRB_ELEMENT_SIZE;
4627 pThis->hCorbDmaTask = NIL_PDMTASKHANDLE;
4628
4629 /** @todo r=bird: There are probably other things which should be
4630 * initialized here before we start failing. */
4631
4632 /*
4633 * Validate and read configuration.
4634 */
4635 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
4636 "BufSizeInMs"
4637 "|BufSizeOutMs"
4638 "|InitialDelayMs"
4639 "|TimerHz"
4640 "|PosAdjustEnabled"
4641 "|PosAdjustFrames"
4642 "|TransferHeuristicsEnabled"
4643 "|DebugEnabled"
4644 "|DebugPathOut",
4645 "");
4646
4647 /** @devcfgm{hda,BufSizeInMs,uint16_t,0,2000,0,ms}
4648 * The size of the DMA buffer for input streams expressed in milliseconds. */
4649 int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeInMs", &pThis->cMsCircBufIn, 0);
4650 if (RT_FAILURE(rc))
4651 return PDMDEV_SET_ERROR(pDevIns, rc,
4652 N_("HDA configuration error: failed to read 'BufSizeInMs' as 16-bit unsigned integer"));
4653 if (pThis->cMsCircBufIn > 2000)
4654 return PDMDEV_SET_ERROR(pDevIns, VERR_OUT_OF_RANGE,
4655 N_("HDA configuration error: 'BufSizeInMs' is out of bound, max 2000 ms"));
4656
4657 /** @devcfgm{hda,BufSizeOutMs,uint16_t,0,2000,0,ms}
4658 * The size of the DMA buffer for output streams expressed in milliseconds. */
4659 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeOutMs", &pThis->cMsCircBufOut, 0);
4660 if (RT_FAILURE(rc))
4661 return PDMDEV_SET_ERROR(pDevIns, rc,
4662 N_("HDA configuration error: failed to read 'BufSizeOutMs' as 16-bit unsigned integer"));
4663 if (pThis->cMsCircBufOut > 2000)
4664 return PDMDEV_SET_ERROR(pDevIns, VERR_OUT_OF_RANGE,
4665 N_("HDA configuration error: 'BufSizeOutMs' is out of bound, max 2000 ms"));
4666
4667 /** @todo uTimerHz isn't used for anything anymore. */
4668 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "TimerHz", &pThis->uTimerHz, HDA_TIMER_HZ_DEFAULT);
4669 if (RT_FAILURE(rc))
4670 return PDMDEV_SET_ERROR(pDevIns, rc,
4671 N_("HDA configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
4672 if (pThis->uTimerHz != HDA_TIMER_HZ_DEFAULT)
4673 LogRel(("HDA: Using custom device timer rate (%RU16Hz)\n", pThis->uTimerHz));
4674
4675 /** @devcfgm{hda,InitialDelayMs,uint16_t,0,256,12,ms}
4676 * How long to delay when a stream starts before engaging the asynchronous I/O
4677 * thread from the DMA timer callback. Because it's used from the DMA timer
4678 * callback, it will implicitly be rounded up to the next timer period.
4679 * This is for adding a little host scheduling leeway into the playback. */
4680 /** @todo InitialDelayMs is rather pointless, DrvAudio does pre-buffering in
4681 * both directions now. (bird, 2021-06-08) */
4682 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "InitialDelayMs", &pThis->msInitialDelay, 12);
4683 if (RT_FAILURE(rc))
4684 return PDMDEV_SET_ERROR(pDevIns, rc, N_("HDA configuration error: failed to read 'InitialDelayMs' as uint16_t"));
4685 if (pThis->msInitialDelay > 256)
4686 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4687 N_("HDA configuration error: Out of range: 0 <= InitialDelayMs < 256: %u"), pThis->msInitialDelay);
4688
4689 /** @todo fPosAdjustEnabled is not honored anymore. */
4690 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "PosAdjustEnabled", &pThis->fPosAdjustEnabled, true);
4691 if (RT_FAILURE(rc))
4692 return PDMDEV_SET_ERROR(pDevIns, rc,
4693 N_("HDA configuration error: failed to read position adjustment enabled as boolean"));
4694 if (!pThis->fPosAdjustEnabled)
4695 LogRel(("HDA: Position adjustment is disabled\n"));
4696
4697 /** @todo cPosAdjustFrames is not consulted anymore. */
4698 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "PosAdjustFrames", &pThis->cPosAdjustFrames, HDA_POS_ADJUST_DEFAULT);
4699 if (RT_FAILURE(rc))
4700 return PDMDEV_SET_ERROR(pDevIns, rc,
4701 N_("HDA configuration error: failed to read position adjustment frames as unsigned integer"));
4702 if (pThis->cPosAdjustFrames)
4703 LogRel(("HDA: Using custom position adjustment (%RU16 audio frames)\n", pThis->cPosAdjustFrames));
4704
4705 /** @todo fTransferHeuristicsEnabled is not used anymore. */
4706 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "TransferHeuristicsEnabled", &pThis->fTransferHeuristicsEnabled, true);
4707 if (RT_FAILURE(rc))
4708 return PDMDEV_SET_ERROR(pDevIns, rc,
4709 N_("HDA configuration error: failed to read data transfer heuristics enabled as boolean"));
4710 if (!pThis->fTransferHeuristicsEnabled)
4711 LogRel(("HDA: Data transfer heuristics are disabled\n"));
4712
4713 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DebugEnabled", &pThisCC->Dbg.fEnabled, false);
4714 if (RT_FAILURE(rc))
4715 return PDMDEV_SET_ERROR(pDevIns, rc,
4716 N_("HDA configuration error: failed to read debugging enabled flag as boolean"));
4717
4718 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "DebugPathOut", &pThisCC->Dbg.pszOutPath, NULL);
4719 if (RT_FAILURE(rc))
4720 return PDMDEV_SET_ERROR(pDevIns, rc,
4721 N_("HDA configuration error: failed to read debugging output path flag as string"));
4722 if (pThisCC->Dbg.fEnabled)
4723 LogRel2(("HDA: Debug output will be saved to '%s'\n", pThisCC->Dbg.pszOutPath));
4724
4725 /*
4726 * Use our own critical section for the device instead of the default
4727 * one provided by PDM. This allows fine-grained locking in combination
4728 * with TM when timer-specific stuff is being called in e.g. the MMIO handlers.
4729 */
4730 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "HDA");
4731 AssertRCReturn(rc, rc);
4732
4733 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
4734 AssertRCReturn(rc, rc);
4735
4736 /*
4737 * Initialize data (most of it anyway).
4738 */
4739 pThisCC->pDevIns = pDevIns;
4740 /* IBase */
4741 pThisCC->IBase.pfnQueryInterface = hdaR3QueryInterface;
4742
4743 /* PCI Device */
4744 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
4745 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
4746
4747 PDMPciDevSetVendorId( pPciDev, HDA_PCI_VENDOR_ID); /* nVidia */
4748 PDMPciDevSetDeviceId( pPciDev, HDA_PCI_DEVICE_ID); /* HDA */
4749
4750 PDMPciDevSetCommand( pPciDev, 0x0000); /* 04 rw,ro - pcicmd. */
4751 PDMPciDevSetStatus( pPciDev, VBOX_PCI_STATUS_CAP_LIST); /* 06 rwc?,ro? - pcists. */
4752 PDMPciDevSetRevisionId( pPciDev, 0x01); /* 08 ro - rid. */
4753 PDMPciDevSetClassProg( pPciDev, 0x00); /* 09 ro - pi. */
4754 PDMPciDevSetClassSub( pPciDev, 0x03); /* 0a ro - scc; 03 == HDA. */
4755 PDMPciDevSetClassBase( pPciDev, 0x04); /* 0b ro - bcc; 04 == multimedia. */
4756 PDMPciDevSetHeaderType( pPciDev, 0x00); /* 0e ro - headtyp. */
4757 PDMPciDevSetBaseAddress( pPciDev, 0, /* 10 rw - MMIO */
4758 false /* fIoSpace */, false /* fPrefetchable */, true /* f64Bit */, 0x00000000);
4759 PDMPciDevSetInterruptLine( pPciDev, 0x00); /* 3c rw. */
4760 PDMPciDevSetInterruptPin( pPciDev, 0x01); /* 3d ro - INTA#. */
4761
4762# if defined(HDA_AS_PCI_EXPRESS)
4763 PDMPciDevSetCapabilityList(pPciDev, 0x80);
4764# elif defined(VBOX_WITH_MSI_DEVICES)
4765 PDMPciDevSetCapabilityList(pPciDev, 0x60);
4766# else
4767 PDMPciDevSetCapabilityList(pPciDev, 0x50); /* ICH6 datasheet 18.1.16 */
4768# endif
4769
4770 /// @todo r=michaln: If there are really no PDMPciDevSetXx for these, the
4771 /// meaning of these values needs to be properly documented!
4772 /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
4773 PDMPciDevSetByte( pPciDev, 0x40, 0x01);
4774
4775 /* Power Management */
4776 PDMPciDevSetByte( pPciDev, 0x50 + 0, VBOX_PCI_CAP_ID_PM);
4777 PDMPciDevSetByte( pPciDev, 0x50 + 1, 0x0); /* next */
4778 PDMPciDevSetWord( pPciDev, 0x50 + 2, VBOX_PCI_PM_CAP_DSI | 0x02 /* version, PM1.1 */ );
4779
4780# ifdef HDA_AS_PCI_EXPRESS
4781 /* PCI Express */
4782 PDMPciDevSetByte( pPciDev, 0x80 + 0, VBOX_PCI_CAP_ID_EXP); /* PCI_Express */
4783 PDMPciDevSetByte( pPciDev, 0x80 + 1, 0x60); /* next */
4784 /* Device flags */
4785 PDMPciDevSetWord( pPciDev, 0x80 + 2,
4786 1 /* version */
4787 | (VBOX_PCI_EXP_TYPE_ROOT_INT_EP << 4) /* Root Complex Integrated Endpoint */
4788 | (100 << 9) /* MSI */ );
4789 /* Device capabilities */
4790 PDMPciDevSetDWord( pPciDev, 0x80 + 4, VBOX_PCI_EXP_DEVCAP_FLRESET);
4791 /* Device control */
4792 PDMPciDevSetWord( pPciDev, 0x80 + 8, 0);
4793 /* Device status */
4794 PDMPciDevSetWord( pPciDev, 0x80 + 10, 0);
4795 /* Link caps */
4796 PDMPciDevSetDWord( pPciDev, 0x80 + 12, 0);
4797 /* Link control */
4798 PDMPciDevSetWord( pPciDev, 0x80 + 16, 0);
4799 /* Link status */
4800 PDMPciDevSetWord( pPciDev, 0x80 + 18, 0);
4801 /* Slot capabilities */
4802 PDMPciDevSetDWord( pPciDev, 0x80 + 20, 0);
4803 /* Slot control */
4804 PDMPciDevSetWord( pPciDev, 0x80 + 24, 0);
4805 /* Slot status */
4806 PDMPciDevSetWord( pPciDev, 0x80 + 26, 0);
4807 /* Root control */
4808 PDMPciDevSetWord( pPciDev, 0x80 + 28, 0);
4809 /* Root capabilities */
4810 PDMPciDevSetWord( pPciDev, 0x80 + 30, 0);
4811 /* Root status */
4812 PDMPciDevSetDWord( pPciDev, 0x80 + 32, 0);
4813 /* Device capabilities 2 */
4814 PDMPciDevSetDWord( pPciDev, 0x80 + 36, 0);
4815 /* Device control 2 */
4816 PDMPciDevSetQWord( pPciDev, 0x80 + 40, 0);
4817 /* Link control 2 */
4818 PDMPciDevSetQWord( pPciDev, 0x80 + 48, 0);
4819 /* Slot control 2 */
4820 PDMPciDevSetWord( pPciDev, 0x80 + 56, 0);
4821# endif /* HDA_AS_PCI_EXPRESS */
4822
4823 /*
4824 * Register the PCI device.
4825 */
4826 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
4827 AssertRCReturn(rc, rc);
4828
4829 /** @todo r=bird: The IOMMMIO_FLAGS_READ_DWORD flag isn't entirely optimal,
4830 * as several frequently used registers aren't dword sized. 6.0 and earlier
4831 * will go to ring-3 to handle accesses to any such register, where-as 6.1 and
4832 * later will do trivial register reads in ring-0. Real optimal code would use
4833 * IOMMMIO_FLAGS_READ_PASSTHRU and do the necessary extra work to deal with
4834 * anything the guest may throw at us. */
4835 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 0, 0x4000, PCI_ADDRESS_SPACE_MEM, hdaMmioWrite, hdaMmioRead, NULL /*pvUser*/,
4836 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU, "HDA", &pThis->hMmio);
4837 AssertRCReturn(rc, rc);
4838
4839# ifdef VBOX_WITH_MSI_DEVICES
4840 PDMMSIREG MsiReg;
4841 RT_ZERO(MsiReg);
4842 MsiReg.cMsiVectors = 1;
4843 MsiReg.iMsiCapOffset = 0x60;
4844 MsiReg.iMsiNextOffset = 0x50;
4845 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
4846 if (RT_FAILURE(rc))
4847 {
4848 /* That's OK, we can work without MSI */
4849 PDMPciDevSetCapabilityList(pPciDev, 0x50);
4850 }
4851# endif
4852
4853 /* Create task for continuing CORB DMA in ring-3. */
4854 rc = PDMDevHlpTaskCreate(pDevIns, PDMTASK_F_RZ, "HDA CORB DMA",
4855 hdaR3CorbDmaTaskWorker, NULL /*pvUser*/, &pThis->hCorbDmaTask);
4856 AssertRCReturn(rc,rc);
4857
4858 rc = PDMDevHlpSSMRegisterEx(pDevIns, HDA_SAVED_STATE_VERSION, sizeof(*pThis), NULL /*pszBefore*/,
4859 NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/,
4860 NULL /*pfnSavePrep*/, hdaR3SaveExec, NULL /*pfnSaveDone*/,
4861 NULL /*pfnLoadPrep*/, hdaR3LoadExec, hdaR3LoadDone);
4862 AssertRCReturn(rc, rc);
4863
4864 /*
4865 * Attach drivers. We ASSUME they are configured consecutively without any
4866 * gaps, so we stop when we hit the first LUN w/o a driver configured.
4867 */
4868 for (unsigned iLun = 0; ; iLun++)
4869 {
4870 AssertBreak(iLun < UINT8_MAX);
4871 LogFunc(("Trying to attach driver for LUN#%u ...\n", iLun));
4872 rc = hdaR3AttachInternal(pDevIns, pThis, pThisCC, iLun, NULL /* ppDrv */);
4873 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4874 {
4875 LogFunc(("cLUNs=%u\n", iLun));
4876 break;
4877 }
4878 AssertLogRelMsgReturn(RT_SUCCESS(rc), ("LUN#%u: rc=%Rrc\n", iLun, rc), rc);
4879 }
4880
4881 /*
4882 * Create the mixer.
4883 */
4884 uint32_t fMixer = AUDMIXER_FLAGS_NONE;
4885 if (pThisCC->Dbg.fEnabled)
4886 fMixer |= AUDMIXER_FLAGS_DEBUG;
4887 rc = AudioMixerCreate("HDA Mixer", fMixer, &pThisCC->pMixer);
4888 AssertRCReturn(rc, rc);
4889
4890 /*
4891 * Add mixer output sinks.
4892 */
4893# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
4894 rc = AudioMixerCreateSink(pThisCC->pMixer, "Front",
4895 PDMAUDIODIR_OUT, pDevIns, &pThisCC->SinkFront.pMixSink);
4896 AssertRCReturn(rc, rc);
4897 rc = AudioMixerCreateSink(pThisCC->pMixer, "Center+Subwoofer",
4898 PDMAUDIODIR_OUT, pDevIns, &pThisCC->SinkCenterLFE.pMixSink);
4899 AssertRCReturn(rc, rc);
4900 rc = AudioMixerCreateSink(pThisCC->pMixer, "Rear",
4901 PDMAUDIODIR_OUT, pDevIns, &pThisCC->SinkRear.pMixSink);
4902 AssertRCReturn(rc, rc);
4903# else
4904 rc = AudioMixerCreateSink(pThisCC->pMixer, "PCM Output",
4905 PDMAUDIODIR_OUT, pDevIns, &pThisCC->SinkFront.pMixSink);
4906 AssertRCReturn(rc, rc);
4907# endif /* VBOX_WITH_AUDIO_HDA_51_SURROUND */
4908
4909 /*
4910 * Add mixer input sinks.
4911 */
4912 rc = AudioMixerCreateSink(pThisCC->pMixer, "Line In",
4913 PDMAUDIODIR_IN, pDevIns, &pThisCC->SinkLineIn.pMixSink);
4914 AssertRCReturn(rc, rc);
4915# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
4916 rc = AudioMixerCreateSink(pThisCC->pMixer, "Microphone In",
4917 PDMAUDIODIR_IN, pDevIns, &pThisCC->SinkMicIn.pMixSink);
4918 AssertRCReturn(rc, rc);
4919# endif
4920
4921 /* There is no master volume control. Set the master to max. */
4922 PDMAUDIOVOLUME Vol = PDMAUDIOVOLUME_INITIALIZER_MAX;
4923 rc = AudioMixerSetMasterVolume(pThisCC->pMixer, &Vol);
4924 AssertRCReturn(rc, rc);
4925
4926 /* Allocate codec. */
4927 PHDACODECR3 pCodecR3 = (PHDACODECR3)RTMemAllocZ(sizeof(HDACODECR3));
4928 AssertPtrReturn(pCodecR3, VERR_NO_MEMORY);
4929
4930 /* Set codec callbacks to this controller. */
4931 pCodecR3->pDevIns = pDevIns;
4932 pCodecR3->pfnCbMixerAddStream = hdaR3MixerAddStream;
4933 pCodecR3->pfnCbMixerRemoveStream = hdaR3MixerRemoveStream;
4934 pCodecR3->pfnCbMixerControl = hdaR3MixerControl;
4935 pCodecR3->pfnCbMixerSetVolume = hdaR3MixerSetVolume;
4936
4937 /* Construct the common + R3 codec part. */
4938 rc = hdaR3CodecConstruct(pDevIns, &pThis->Codec, pCodecR3, 0 /* Codec index */, pCfg);
4939 AssertRCReturn(rc, rc);
4940
4941 pThisCC->pCodec = pCodecR3;
4942
4943 /* ICH6 datasheet defines 0 values for SVID and SID (18.1.14-15), which together with values returned for
4944 verb F20 should provide device/codec recognition. */
4945 Assert(pThis->Codec.u16VendorId);
4946 Assert(pThis->Codec.u16DeviceId);
4947 PDMPciDevSetSubSystemVendorId(pPciDev, pThis->Codec.u16VendorId); /* 2c ro - intel.) */
4948 PDMPciDevSetSubSystemId( pPciDev, pThis->Codec.u16DeviceId); /* 2e ro. */
4949
4950 /*
4951 * Create the per stream timers and the asso.
4952 *
4953 * We must the critical section for the timers as the device has a
4954 * noop section associated with it.
4955 *
4956 * Note: Use TMCLOCK_VIRTUAL_SYNC here, as the guest's HDA driver relies
4957 * on exact (virtual) DMA timing and uses DMA Position Buffers
4958 * instead of the LPIB registers.
4959 */
4960 /** @todo r=bird: The need to use virtual sync is perhaps because TM
4961 * doesn't schedule regular TMCLOCK_VIRTUAL timers as accurately as it
4962 * should (VT-x preemption timer, etc). Hope to address that before
4963 * long. @bugref{9943}. */
4964 static const char * const s_apszNames[] =
4965 { "HDA SD0", "HDA SD1", "HDA SD2", "HDA SD3", "HDA SD4", "HDA SD5", "HDA SD6", "HDA SD7", };
4966 AssertCompile(RT_ELEMENTS(s_apszNames) == HDA_MAX_STREAMS);
4967 for (size_t i = 0; i < HDA_MAX_STREAMS; i++)
4968 {
4969 /* We need the first timer in ring-0 to calculate the wall clock (WALCLK) time. */
4970 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hdaR3Timer, (void *)(uintptr_t)i,
4971 TMTIMER_FLAGS_NO_CRIT_SECT | (i == 0 ? TMTIMER_FLAGS_RING0 : TMTIMER_FLAGS_NO_RING0),
4972 s_apszNames[i], &pThis->aStreams[i].hTimer);
4973 AssertRCReturn(rc, rc);
4974
4975 rc = PDMDevHlpTimerSetCritSect(pDevIns, pThis->aStreams[i].hTimer, &pThis->CritSect);
4976 AssertRCReturn(rc, rc);
4977 }
4978
4979 /*
4980 * Create all hardware streams.
4981 */
4982 for (uint8_t i = 0; i < HDA_MAX_STREAMS; ++i)
4983 {
4984 rc = hdaR3StreamConstruct(&pThis->aStreams[i], &pThisCC->aStreams[i], pThis, pThisCC, i /* u8SD */);
4985 AssertRCReturn(rc, rc);
4986 }
4987
4988 hdaR3Reset(pDevIns);
4989
4990 /*
4991 * Info items and string formatter types. The latter is non-optional as
4992 * the info handles use (at least some of) the custom types and we cannot
4993 * accept screwing formatting.
4994 */
4995 PDMDevHlpDBGFInfoRegister(pDevIns, "hda", "HDA registers. (hda [register case-insensitive])", hdaR3DbgInfo);
4996 PDMDevHlpDBGFInfoRegister(pDevIns, "hdabdl",
4997 "HDA buffer descriptor list (BDL) and DMA stream positions. (hdabdl [stream number])",
4998 hdaR3DbgInfoBDL);
4999 PDMDevHlpDBGFInfoRegister(pDevIns, "hdastream", "HDA stream info. (hdastream [stream number])", hdaR3DbgInfoStream);
5000 PDMDevHlpDBGFInfoRegister(pDevIns, "hdcnodes", "HDA codec nodes.", hdaR3DbgInfoCodecNodes);
5001 PDMDevHlpDBGFInfoRegister(pDevIns, "hdcselector", "HDA codec's selector states [node number].", hdaR3DbgInfoCodecSelector);
5002 PDMDevHlpDBGFInfoRegister(pDevIns, "hdamixer", "HDA mixer state.", hdaR3DbgInfoMixer);
5003
5004 rc = RTStrFormatTypeRegister("sdctl", hdaR3StrFmtSDCTL, NULL);
5005 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5006 rc = RTStrFormatTypeRegister("sdsts", hdaR3StrFmtSDSTS, NULL);
5007 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5008 /** @todo the next two are rather pointless. */
5009 rc = RTStrFormatTypeRegister("sdfifos", hdaR3StrFmtSDFIFOS, NULL);
5010 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5011 rc = RTStrFormatTypeRegister("sdfifow", hdaR3StrFmtSDFIFOW, NULL);
5012 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5013
5014 /*
5015 * Asserting sanity.
5016 */
5017 for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
5018 {
5019 struct HDAREGDESC const *pReg = &g_aHdaRegMap[i];
5020 struct HDAREGDESC const *pNextReg = i + 1 < RT_ELEMENTS(g_aHdaRegMap) ? &g_aHdaRegMap[i + 1] : NULL;
5021
5022 /* binary search order. */
5023 AssertReleaseMsg(!pNextReg || pReg->offset + pReg->size <= pNextReg->offset,
5024 ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
5025 i, pReg->offset, pReg->size, i + 1, pNextReg->offset, pNextReg->size));
5026
5027 /* alignment. */
5028 AssertReleaseMsg( pReg->size == 1
5029 || (pReg->size == 2 && (pReg->offset & 1) == 0)
5030 || (pReg->size == 3 && (pReg->offset & 3) == 0)
5031 || (pReg->size == 4 && (pReg->offset & 3) == 0),
5032 ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
5033
5034 /* registers are packed into dwords - with 3 exceptions with gaps at the end of the dword. */
5035 AssertRelease(((pReg->offset + pReg->size) & 3) == 0 || pNextReg);
5036 if (pReg->offset & 3)
5037 {
5038 struct HDAREGDESC const *pPrevReg = i > 0 ? &g_aHdaRegMap[i - 1] : NULL;
5039 AssertReleaseMsg(pPrevReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
5040 if (pPrevReg)
5041 AssertReleaseMsg(pPrevReg->offset + pPrevReg->size == pReg->offset,
5042 ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
5043 i - 1, pPrevReg->offset, pPrevReg->size, i + 1, pReg->offset, pReg->size));
5044 }
5045#if 0
5046 if ((pReg->offset + pReg->size) & 3)
5047 {
5048 AssertReleaseMsg(pNextReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
5049 if (pNextReg)
5050 AssertReleaseMsg(pReg->offset + pReg->size == pNextReg->offset,
5051 ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
5052 i, pReg->offset, pReg->size, i + 1, pNextReg->offset, pNextReg->size));
5053 }
5054#endif
5055 /* The final entry is a full DWORD, no gaps! Allows shortcuts. */
5056 AssertReleaseMsg(pNextReg || ((pReg->offset + pReg->size) & 3) == 0,
5057 ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
5058 }
5059
5060# ifdef VBOX_WITH_STATISTICS
5061 /*
5062 * Register statistics.
5063 */
5064 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn, STAMTYPE_PROFILE, "Input", STAMUNIT_TICKS_PER_CALL, "Profiling input.");
5065 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatOut, STAMTYPE_PROFILE, "Output", STAMUNIT_TICKS_PER_CALL, "Profiling output.");
5066 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, "BytesRead" , STAMUNIT_BYTES, "Bytes read from HDA emulation.");
5067 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "BytesWritten", STAMUNIT_BYTES, "Bytes written to HDA emulation.");
5068
5069 AssertCompile(RT_ELEMENTS(g_aHdaRegMap) == HDA_NUM_REGS);
5070 AssertCompile(RT_ELEMENTS(pThis->aStatRegReads) == HDA_NUM_REGS);
5071 AssertCompile(RT_ELEMENTS(pThis->aStatRegReadsToR3) == HDA_NUM_REGS);
5072 AssertCompile(RT_ELEMENTS(pThis->aStatRegWrites) == HDA_NUM_REGS);
5073 AssertCompile(RT_ELEMENTS(pThis->aStatRegWritesToR3) == HDA_NUM_REGS);
5074 for (size_t i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
5075 {
5076 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegReads[i], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
5077 g_aHdaRegMap[i].desc, "Regs/%03x-%s-Reads", g_aHdaRegMap[i].offset, g_aHdaRegMap[i].abbrev);
5078 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegReadsToR3[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5079 g_aHdaRegMap[i].desc, "Regs/%03x-%s-Reads-ToR3", g_aHdaRegMap[i].offset, g_aHdaRegMap[i].abbrev);
5080 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegWrites[i], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
5081 g_aHdaRegMap[i].desc, "Regs/%03x-%s-Writes", g_aHdaRegMap[i].offset, g_aHdaRegMap[i].abbrev);
5082 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegWritesToR3[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5083 g_aHdaRegMap[i].desc, "Regs/%03x-%s-Writes-ToR3", g_aHdaRegMap[i].offset, g_aHdaRegMap[i].abbrev);
5084 }
5085 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiReadsR3, STAMTYPE_COUNTER, "RegMultiReadsR3", STAMUNIT_OCCURENCES, "Register read not targeting just one register, handled in ring-3");
5086 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiReadsRZ, STAMTYPE_COUNTER, "RegMultiReadsRZ", STAMUNIT_OCCURENCES, "Register read not targeting just one register, handled in ring-0");
5087 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiWritesR3, STAMTYPE_COUNTER, "RegMultiWritesR3", STAMUNIT_OCCURENCES, "Register writes not targeting just one register, handled in ring-3");
5088 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiWritesRZ, STAMTYPE_COUNTER, "RegMultiWritesRZ", STAMUNIT_OCCURENCES, "Register writes not targeting just one register, handled in ring-0");
5089 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegSubWriteR3, STAMTYPE_COUNTER, "RegSubWritesR3", STAMUNIT_OCCURENCES, "Trucated register writes, handled in ring-3");
5090 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegSubWriteRZ, STAMTYPE_COUNTER, "RegSubWritesRZ", STAMUNIT_OCCURENCES, "Trucated register writes, handled in ring-0");
5091 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegUnknownReads, STAMTYPE_COUNTER, "RegUnknownReads", STAMUNIT_OCCURENCES, "Reads of unknown registers.");
5092 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegUnknownWrites, STAMTYPE_COUNTER, "RegUnknownWrites", STAMUNIT_OCCURENCES, "Writes to unknown registers.");
5093 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegWritesBlockedByReset, STAMTYPE_COUNTER, "RegWritesBlockedByReset", STAMUNIT_OCCURENCES, "Writes blocked by pending reset (GCTL/CRST)");
5094 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegWritesBlockedByRun, STAMTYPE_COUNTER, "RegWritesBlockedByRun", STAMUNIT_OCCURENCES, "Writes blocked by byte RUN bit.");
5095# endif
5096
5097 for (uint8_t idxStream = 0; idxStream < RT_ELEMENTS(pThisCC->aStreams); idxStream++)
5098 {
5099 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowProblems, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5100 "Number of internal DMA buffer problems.", "Stream%u/DMABufferProblems", idxStream);
5101 if (hdaGetDirFromSD(idxStream) == PDMAUDIODIR_OUT)
5102 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5103 "Number of internal DMA buffer overflows.", "Stream%u/DMABufferOverflows", idxStream);
5104 else
5105 {
5106 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5107 "Number of internal DMA buffer underuns.", "Stream%u/DMABufferUnderruns", idxStream);
5108 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrorBytes, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5109 "Number of bytes of silence added to cope with underruns.", "Stream%u/DMABufferSilence", idxStream);
5110 }
5111 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.offRead, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5112 "Virtual internal buffer read position.", "Stream%u/offRead", idxStream);
5113 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.offWrite, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5114 "Virtual internal buffer write position.", "Stream%u/offWrite", idxStream);
5115 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.cbTransferSize, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5116 "Bytes transfered per DMA timer callout.", "Stream%u/cbTransferSize", idxStream);
5117 PDMDevHlpSTAMRegisterF(pDevIns, (void*)&pThis->aStreams[idxStream].State.fRunning, STAMTYPE_BOOL, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5118 "True if the stream is in RUN mode.", "Stream%u/fRunning", idxStream);
5119 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.uHz, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_HZ,
5120 "The stream frequency.", "Stream%u/Cfg/Hz", idxStream);
5121 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cbFrame, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5122 "The frame size.", "Stream%u/Cfg/FrameSize", idxStream);
5123#if 0 /** @todo this would require some callback or expansion. */
5124 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cChannelsX, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5125 "The number of channels.", "Stream%u/Cfg/Channels-Host", idxStream);
5126 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.Mapping.GuestProps.cChannels, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5127 "The number of channels.", "Stream%u/Cfg/Channels-Guest", idxStream);
5128 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].State.Cfg.Props.cbSample, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5129 "The size of a sample (per channel).", "Stream%u/Cfg/cbSample", idxStream);
5130#endif
5131
5132 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaBufSize, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5133 "Size of the internal DMA buffer.", "Stream%u/DMABufSize", idxStream);
5134 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaBufUsed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
5135 "Number of bytes used in the internal DMA buffer.", "Stream%u/DMABufUsed", idxStream);
5136
5137 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatStart, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
5138 "Starting the stream.", "Stream%u/Start", idxStream);
5139 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatStop, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
5140 "Stopping the stream.", "Stream%u/Stop", idxStream);
5141 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatReset, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
5142 "Resetting the stream.", "Stream%u/Reset", idxStream);
5143 }
5144
5145 return VINF_SUCCESS;
5146}
5147
5148#else /* !IN_RING3 */
5149
5150/**
5151 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
5152 */
5153static DECLCALLBACK(int) hdaRZConstruct(PPDMDEVINS pDevIns)
5154{
5155 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* this shall come first */
5156 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
5157 PHDASTATER0 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER0);
5158
5159 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
5160 AssertRCReturn(rc, rc);
5161
5162 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, hdaMmioWrite, hdaMmioRead, NULL /*pvUser*/);
5163 AssertRCReturn(rc, rc);
5164
5165# if 0 /* Codec is not yet kosher enough for ring-0. @bugref{9890c64} */
5166 /* Construct the R0 codec part. */
5167 rc = hdaR0CodecConstruct(pDevIns, &pThis->Codec, &pThisCC->Codec);
5168 AssertRCReturn(rc, rc);
5169# else
5170 RT_NOREF(pThisCC);
5171# endif
5172
5173 return VINF_SUCCESS;
5174}
5175
5176#endif /* !IN_RING3 */
5177
5178/**
5179 * The device registration structure.
5180 */
5181const PDMDEVREG g_DeviceHDA =
5182{
5183 /* .u32Version = */ PDM_DEVREG_VERSION,
5184 /* .uReserved0 = */ 0,
5185 /* .szName = */ "hda",
5186 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
5187 | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION /* stream clearnup with working drivers */,
5188 /* .fClass = */ PDM_DEVREG_CLASS_AUDIO,
5189 /* .cMaxInstances = */ 1,
5190 /* .uSharedVersion = */ 42,
5191 /* .cbInstanceShared = */ sizeof(HDASTATE),
5192 /* .cbInstanceCC = */ CTX_EXPR(sizeof(HDASTATER3), sizeof(HDASTATER0), 0),
5193 /* .cbInstanceRC = */ 0,
5194 /* .cMaxPciDevices = */ 1,
5195 /* .cMaxMsixVectors = */ 0,
5196 /* .pszDescription = */ "Intel HD Audio Controller",
5197#if defined(IN_RING3)
5198 /* .pszRCMod = */ "VBoxDDRC.rc",
5199 /* .pszR0Mod = */ "VBoxDDR0.r0",
5200 /* .pfnConstruct = */ hdaR3Construct,
5201 /* .pfnDestruct = */ hdaR3Destruct,
5202 /* .pfnRelocate = */ NULL,
5203 /* .pfnMemSetup = */ NULL,
5204 /* .pfnPowerOn = */ NULL,
5205 /* .pfnReset = */ hdaR3Reset,
5206 /* .pfnSuspend = */ NULL,
5207 /* .pfnResume = */ NULL,
5208 /* .pfnAttach = */ hdaR3Attach,
5209 /* .pfnDetach = */ hdaR3Detach,
5210 /* .pfnQueryInterface = */ NULL,
5211 /* .pfnInitComplete = */ NULL,
5212 /* .pfnPowerOff = */ hdaR3PowerOff,
5213 /* .pfnSoftReset = */ NULL,
5214 /* .pfnReserved0 = */ NULL,
5215 /* .pfnReserved1 = */ NULL,
5216 /* .pfnReserved2 = */ NULL,
5217 /* .pfnReserved3 = */ NULL,
5218 /* .pfnReserved4 = */ NULL,
5219 /* .pfnReserved5 = */ NULL,
5220 /* .pfnReserved6 = */ NULL,
5221 /* .pfnReserved7 = */ NULL,
5222#elif defined(IN_RING0)
5223 /* .pfnEarlyConstruct = */ NULL,
5224 /* .pfnConstruct = */ hdaRZConstruct,
5225 /* .pfnDestruct = */ NULL,
5226 /* .pfnFinalDestruct = */ NULL,
5227 /* .pfnRequest = */ NULL,
5228 /* .pfnReserved0 = */ NULL,
5229 /* .pfnReserved1 = */ NULL,
5230 /* .pfnReserved2 = */ NULL,
5231 /* .pfnReserved3 = */ NULL,
5232 /* .pfnReserved4 = */ NULL,
5233 /* .pfnReserved5 = */ NULL,
5234 /* .pfnReserved6 = */ NULL,
5235 /* .pfnReserved7 = */ NULL,
5236#elif defined(IN_RC)
5237 /* .pfnConstruct = */ hdaRZConstruct,
5238 /* .pfnReserved0 = */ NULL,
5239 /* .pfnReserved1 = */ NULL,
5240 /* .pfnReserved2 = */ NULL,
5241 /* .pfnReserved3 = */ NULL,
5242 /* .pfnReserved4 = */ NULL,
5243 /* .pfnReserved5 = */ NULL,
5244 /* .pfnReserved6 = */ NULL,
5245 /* .pfnReserved7 = */ NULL,
5246#else
5247# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5248#endif
5249 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
5250};
5251
5252#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
5253
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