VirtualBox

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

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

Audio: Made sure PDMAUDIOPCMPROPS is initialized using a helper function or the initializer macro, and that vital changes are made using setting helper functions. There are now two derived fields (frame size and shift count) that must be maintained, so this was the sanest way of doing it. Added a raw flag to PDMAUDIOPCMPROPS for VRDE/VRDP, since it wants the raw mixer content and we need a way of expressing this (PDMAUDIOSTREAMLAYOUT isn't the right place). The mixer buffers now uses PDMAUDIOPCMPROPS rather than the weird 32-bit format contraption for picking conversion functions. Simplify the drvAudioStreamPlay code by eliminating the PDMAUDIOSTREAMLAYOUT_RAW special case. bugref:9890

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

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