VirtualBox

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

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

VMM/TM,VMM/DevHlp: Require flag on timers that are to be used in ring-0 (and while refactoring a counte flag to check that all timers have been checked). Removed obsolete timer device helpers. bugref:9943

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

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