VirtualBox

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

最後變更 在這個檔案從87262是 87262,由 vboxsync 提交於 4 年 前

Audio/HDA: Logging tweaks. ticketoem2ref:36

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

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