VirtualBox

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

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

DevHDA: Count DMA over-/underflows. bugref:9890

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

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