VirtualBox

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

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

DevHDA: Made the DMA timer scheduling heuristics more flexible and ditched the alternative approaches. Changed the DMA engine to load the whole BDL and not reload BDLEs as we work thru them. Ditched the HDABDLE structure and some other DMA related stuff (FIFO buffer is on the todo list). bugref:9890

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

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