VirtualBox

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

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

Audio/HDA: Doxygen fix (it doesn't have VBOX_WITH_AUDIO_HDA_ASYNC_IO defined and got confused by unbalanced {} #ifdefs).

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

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