VirtualBox

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

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

DevHda: fixed direct access to PDMAUDIOPCMPROPS::cChannelsX (verboten). bugref:9890

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