VirtualBox

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

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

AudioMixer: Removed some more unused stuff; cleanups. bugref:9890

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