VirtualBox

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

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

Audio: Added an fImmediate indicator to the pfnStreamDestroy methods so the backend knows whether it's okay to continue draining the stream or if it must be destroyed without delay. The latter is typically only for shutdown and driver plumbing. This helps quite a bit for HDA/CoreAudio/knoppix. bugref:9890

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

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