VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevHDA.cpp@ 82422

Last change on this file since 82422 was 82421, checked in by vboxsync, 5 years ago

DevHDA: Keep the 'hdcnodes' debug info item working in release builds too. bugref:9218

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