VirtualBox

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

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

DevHDA/hdaRegWriteCORBRP: Fixed bug introduced in r135300.

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