VirtualBox

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

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

DevHda: Removed the HDA_USE_DMA_ACCESS_HANDLER stuff as it is unlikely to be helpful. Current assumption is that BDLs are owned by the HDA controller when we're running. (What migth've been useful would be to monitor the DMA position buffer.) bugref:9890

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