VirtualBox

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

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

DevHDA: doxygen fix. bugref:9218

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

© 2023 Oracle
ContactPrivacy policyTerms of Use