VirtualBox

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

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

Audio/Mixer: Implemented mixer creation flags to support runtime debugging mode.

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

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