VirtualBox

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

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

Audio: Reworking the capture (recording) code path, part 1: Start doing device side mixing in preparation of DrvAudio stopping it's mixing. Code for blending/merging more than one input isn't entirely done. Resampling is completely untested. bugref:9890

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette