VirtualBox

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

最後變更 在這個檔案從87936是 87926,由 vboxsync 提交於 4 年 前

doxygen fixing

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

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