VirtualBox

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

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

Audio/Dev*: Must destroy the mixer in the destructor as the power off callback isn't always used. bugref:9890

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