VirtualBox

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

Last change on this file since 85546 was 83812, checked in by vboxsync, 5 years ago

Devices/Audio: VC++ 14.1 warnings. bugref:8498

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

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