VirtualBox

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

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

Audio: Removed PDMAUDIOSTREAMCFG::enmLayout and PDMAUDIOSTREAMLAYOUT. bugref:9890

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

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