VirtualBox

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

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

DevHda: Removed the stream mapping and leave such complications to the mixer buffer. (Still some cleanup to be done here.) bugref:9890

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