VirtualBox

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

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

DevHda: Fixed regression caused by incorrect assumption about ring-0 vs ring-3 code in r142859 where the CORB processing was made ring-0 capable. bugref:9890

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

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