VirtualBox

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

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

HDA/Codec: Codec now also can run in R0 to speed up interrupt handling and therefore lowering DPC latency on Windows guests [build fix]. ticketoem2ref:36

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

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