VirtualBox

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

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

Audio: Added optional pfnStreamConfigHint methods to PDMIAUDIOCONNECTOR and PDMIHOSTAUDIO so the WASAPI backend can get some useful cache hints to avoid potentially horried EMT blocking when the guest tries to play audio later. This is rather crude, but with typical guest config it helps a lot. bugref:9890

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