VirtualBox

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

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

DevHda: Eliminated HDASTREAM::CritSect as it is not necessary. The AIO thread serialization happens via the sink lock, the rest via the device wide critical section. bugref:9890

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