VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevHDA.cpp@ 88164

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

DevHDA: Remove the FIFO buffer. Try align the stream state on cache lines. bugref:9890

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