VirtualBox

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

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

Audio/HDA: Let run hdaRegReadWALCLK() in R0. ticketoem2ref:36

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

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