VirtualBox

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

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

Audio: Buffer usage statistics so we can monitor whether they are emptied when they should be. bugref:9890

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette