VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevHda.cpp@ 89864

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

DevHda: Do LPIB updates more often. Experimental code for doing DMA work on LPIB read (disabled). bugref:9890

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

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