VirtualBox

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

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

Devices/Audio/HDA: Don't return VINF_IOM_R3_MMIO_WRITE in R3 or PGM trips + a todo

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

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