VirtualBox

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

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

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