VirtualBox

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

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

DevHDA: Some debug info handler tweaking; implementing hdaR3DbgLookupStrmIdx. bugref:9890

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

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