VirtualBox

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

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

Audio: Size the mixer buffer for sinks according to the scheulding hint. This should typically reduce the buffer size from the fixed size of 100ms we've used so far, helping to reduce latency build up. Also, 100ms might not have been enough for some configurations. bugref:9890

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