VirtualBox

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

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

Audio: For anyone wishing to use the VBOX_AUDIO_DEBUG_DUMP_PCM_DATA stuff, you now have to define VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH to the output path string. Don't want hardly ever used debug fun like VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH in pdmaudioifs.h. bugref:9890

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