VirtualBox

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

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

Audio/HDA: When starting / resuming (via saved state) stream transfers, call hdaR3StreamTimerMain() directly to avoid going through the timer to speed up startup time. ticketoem2ref:36

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 201.3 KB
 
1/* $Id: DevHDA.cpp 87944 2021-03-04 09:14:58Z 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 /* Avoid going through the timer here by calling the stream's timer function directly.
1441 * Should speed up starting the stream transfers. */
1442 hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
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 hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
2652}
2653
2654# ifdef HDA_USE_DMA_ACCESS_HANDLER
2655/**
2656 * HC access handler for the FIFO.
2657 *
2658 * @returns VINF_SUCCESS if the handler have carried out the operation.
2659 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
2660 * @param pVM VM Handle.
2661 * @param pVCpu The cross context CPU structure for the calling EMT.
2662 * @param GCPhys The physical address the guest is writing to.
2663 * @param pvPhys The HC mapping of that address.
2664 * @param pvBuf What the guest is reading/writing.
2665 * @param cbBuf How much it's reading/writing.
2666 * @param enmAccessType The access type.
2667 * @param enmOrigin Who is making the access.
2668 * @param pvUser User argument.
2669 */
2670static DECLCALLBACK(VBOXSTRICTRC) hdaR3DmaAccessHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void *pvPhys,
2671 void *pvBuf, size_t cbBuf,
2672 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
2673{
2674 RT_NOREF(pVM, pVCpu, pvPhys, pvBuf, enmOrigin);
2675
2676 PHDADMAACCESSHANDLER pHandler = (PHDADMAACCESSHANDLER)pvUser;
2677 AssertPtr(pHandler);
2678
2679 PHDASTREAM pStream = pHandler->pStream;
2680 AssertPtr(pStream);
2681
2682 Assert(GCPhys >= pHandler->GCPhysFirst);
2683 Assert(GCPhys <= pHandler->GCPhysLast);
2684 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
2685
2686 /* Not within BDLE range? Bail out. */
2687 if ( (GCPhys < pHandler->BDLEAddr)
2688 || (GCPhys + cbBuf > pHandler->BDLEAddr + pHandler->BDLESize))
2689 {
2690 return VINF_PGM_HANDLER_DO_DEFAULT;
2691 }
2692
2693 switch (enmAccessType)
2694 {
2695 case PGMACCESSTYPE_WRITE:
2696 {
2697# ifdef DEBUG
2698 PHDASTREAMDEBUG pStreamDbg = &pStream->Dbg;
2699
2700 const uint64_t tsNowNs = RTTimeNanoTS();
2701 const uint32_t tsElapsedMs = (tsNowNs - pStreamDbg->tsWriteSlotBegin) / 1000 / 1000;
2702
2703 uint64_t cWritesHz = ASMAtomicReadU64(&pStreamDbg->cWritesHz);
2704 uint64_t cbWrittenHz = ASMAtomicReadU64(&pStreamDbg->cbWrittenHz);
2705
2706 if (tsElapsedMs >= (1000 / HDA_TIMER_HZ_DEFAULT))
2707 {
2708 LogFunc(("[SD%RU8] %RU32ms elapsed, cbWritten=%RU64, cWritten=%RU64 -- %RU32 bytes on average per time slot (%zums)\n",
2709 pStream->u8SD, tsElapsedMs, cbWrittenHz, cWritesHz,
2710 ASMDivU64ByU32RetU32(cbWrittenHz, cWritesHz ? cWritesHz : 1), 1000 / HDA_TIMER_HZ_DEFAULT));
2711
2712 pStreamDbg->tsWriteSlotBegin = tsNowNs;
2713
2714 cWritesHz = 0;
2715 cbWrittenHz = 0;
2716 }
2717
2718 cWritesHz += 1;
2719 cbWrittenHz += cbBuf;
2720
2721 ASMAtomicIncU64(&pStreamDbg->cWritesTotal);
2722 ASMAtomicAddU64(&pStreamDbg->cbWrittenTotal, cbBuf);
2723
2724 ASMAtomicWriteU64(&pStreamDbg->cWritesHz, cWritesHz);
2725 ASMAtomicWriteU64(&pStreamDbg->cbWrittenHz, cbWrittenHz);
2726
2727 LogFunc(("[SD%RU8] Writing %3zu @ 0x%x (off %zu)\n",
2728 pStream->u8SD, cbBuf, GCPhys, GCPhys - pHandler->BDLEAddr));
2729
2730 LogFunc(("[SD%RU8] cWrites=%RU64, cbWritten=%RU64 -> %RU32 bytes on average\n",
2731 pStream->u8SD, pStreamDbg->cWritesTotal, pStreamDbg->cbWrittenTotal,
2732 ASMDivU64ByU32RetU32(pStreamDbg->cbWrittenTotal, pStreamDbg->cWritesTotal)));
2733# endif
2734
2735# ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
2736 if (pThis->fDebugEnabled)
2737 {
2738 RTFILE fh;
2739 RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaDMAAccessWrite.pcm",
2740 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
2741 RTFileWrite(fh, pvBuf, cbBuf, NULL);
2742 RTFileClose(fh);
2743 }
2744# endif
2745
2746# ifdef HDA_USE_DMA_ACCESS_HANDLER_WRITING
2747 PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
2748 AssertPtr(pCircBuf);
2749
2750 uint8_t *pbBuf = (uint8_t *)pvBuf;
2751 while (cbBuf)
2752 {
2753 /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */
2754 void *pvChunk;
2755 size_t cbChunk;
2756 RTCircBufAcquireWriteBlock(pCircBuf, cbBuf, &pvChunk, &cbChunk);
2757
2758 if (cbChunk)
2759 {
2760 memcpy(pvChunk, pbBuf, cbChunk);
2761
2762 pbBuf += cbChunk;
2763 Assert(cbBuf >= cbChunk);
2764 cbBuf -= cbChunk;
2765 }
2766 else
2767 {
2768 //AssertMsg(RTCircBufFree(pCircBuf), ("No more space but still %zu bytes to write\n", cbBuf));
2769 break;
2770 }
2771
2772 LogFunc(("[SD%RU8] cbChunk=%zu\n", pStream->u8SD, cbChunk));
2773
2774 RTCircBufReleaseWriteBlock(pCircBuf, cbChunk);
2775 }
2776# endif /* HDA_USE_DMA_ACCESS_HANDLER_WRITING */
2777 break;
2778 }
2779
2780 default:
2781 AssertMsgFailed(("Access type not implemented\n"));
2782 break;
2783 }
2784
2785 return VINF_PGM_HANDLER_DO_DEFAULT;
2786}
2787# endif /* HDA_USE_DMA_ACCESS_HANDLER */
2788
2789/**
2790 * Soft reset of the device triggered via GCTL.
2791 *
2792 * @param pDevIns The device instance.
2793 * @param pThis The shared HDA device state.
2794 * @param pThisCC The ring-3 HDA device state.
2795 */
2796static void hdaR3GCTLReset(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC)
2797{
2798 LogFlowFuncEnter();
2799
2800 pThisCC->cStreamsActive = 0;
2801
2802 HDA_REG(pThis, GCAP) = HDA_MAKE_GCAP(HDA_MAX_SDO, HDA_MAX_SDI, 0, 0, 1); /* see 6.2.1 */
2803 HDA_REG(pThis, VMIN) = 0x00; /* see 6.2.2 */
2804 HDA_REG(pThis, VMAJ) = 0x01; /* see 6.2.3 */
2805 HDA_REG(pThis, OUTPAY) = 0x003C; /* see 6.2.4 */
2806 HDA_REG(pThis, INPAY) = 0x001D; /* see 6.2.5 */
2807 HDA_REG(pThis, CORBSIZE) = 0x42; /* Up to 256 CORB entries see 6.2.1 */
2808 HDA_REG(pThis, RIRBSIZE) = 0x42; /* Up to 256 RIRB entries see 6.2.1 */
2809 HDA_REG(pThis, CORBRP) = 0x0;
2810 HDA_REG(pThis, CORBWP) = 0x0;
2811 HDA_REG(pThis, RIRBWP) = 0x0;
2812 /* Some guests (like Haiku) don't set RINTCNT explicitly but expect an interrupt after each
2813 * RIRB response -- so initialize RINTCNT to 1 by default. */
2814 HDA_REG(pThis, RINTCNT) = 0x1;
2815
2816 /*
2817 * Stop any audio currently playing and/or recording.
2818 */
2819 pThisCC->SinkFront.pStreamShared = NULL;
2820 pThisCC->SinkFront.pStreamR3 = NULL;
2821 if (pThisCC->SinkFront.pMixSink)
2822 AudioMixerSinkReset(pThisCC->SinkFront.pMixSink);
2823# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2824 pThisCC->SinkMicIn.pStreamShared = NULL;
2825 pThisCC->SinkMicIn.pStreamR3 = NULL;
2826 if (pThisCC->SinkMicIn.pMixSink)
2827 AudioMixerSinkReset(pThisCC->SinkMicIn.pMixSink);
2828# endif
2829 pThisCC->SinkLineIn.pStreamShared = NULL;
2830 pThisCC->SinkLineIn.pStreamR3 = NULL;
2831 if (pThisCC->SinkLineIn.pMixSink)
2832 AudioMixerSinkReset(pThisCC->SinkLineIn.pMixSink);
2833# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2834 pThisCC->SinkCenterLFE = NULL;
2835 if (pThisCC->SinkCenterLFE.pMixSink)
2836 AudioMixerSinkReset(pThisCC->SinkCenterLFE.pMixSink);
2837 pThisCC->SinkRear.pStreamShared = NULL;
2838 pThisCC->SinkRear.pStreamR3 = NULL;
2839 if (pThisCC->SinkRear.pMixSink)
2840 AudioMixerSinkReset(pThisCC->SinkRear.pMixSink);
2841# endif
2842
2843 /*
2844 * Reset the codec.
2845 */
2846 hdaCodecReset(&pThis->Codec);
2847
2848 /*
2849 * Set some sensible defaults for which HDA sinks
2850 * are connected to which stream number.
2851 *
2852 * We use SD0 for input and SD4 for output by default.
2853 * These stream numbers can be changed by the guest dynamically lateron.
2854 */
2855 ASMCompilerBarrier(); /* paranoia */
2856# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2857 hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_MIC_IN , 1 /* SD0 */, 0 /* Channel */);
2858# endif
2859 hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_LINE_IN , 1 /* SD0 */, 0 /* Channel */);
2860
2861 hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_FRONT , 5 /* SD4 */, 0 /* Channel */);
2862# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2863 hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_CENTER_LFE, 5 /* SD4 */, 0 /* Channel */);
2864 hdaR3MixerControl(pDevIns, PDMAUDIOMIXERCTL_REAR , 5 /* SD4 */, 0 /* Channel */);
2865# endif
2866 ASMCompilerBarrier(); /* paranoia */
2867
2868 /* Reset CORB. */
2869 pThis->cbCorbBuf = HDA_CORB_SIZE * HDA_CORB_ELEMENT_SIZE;
2870 RT_ZERO(pThis->au32CorbBuf);
2871
2872 /* Reset RIRB. */
2873 pThis->cbRirbBuf = HDA_RIRB_SIZE * HDA_RIRB_ELEMENT_SIZE;
2874 RT_ZERO(pThis->au64RirbBuf);
2875
2876 /* Clear our internal response interrupt counter. */
2877 pThis->u16RespIntCnt = 0;
2878
2879 for (size_t idxStream = 0; idxStream < RT_ELEMENTS(pThis->aStreams); idxStream++)
2880 {
2881 int rc2 = hdaR3StreamEnable(&pThis->aStreams[idxStream], &pThisCC->aStreams[idxStream], false /* fEnable */);
2882 if (RT_SUCCESS(rc2))
2883 {
2884 /* Remove the RUN bit from SDnCTL in case the stream was in a running state before. */
2885 HDA_STREAM_REG(pThis, CTL, idxStream) &= ~HDA_SDCTL_RUN;
2886 hdaR3StreamReset(pThis, pThisCC, &pThis->aStreams[idxStream], &pThisCC->aStreams[idxStream], (uint8_t)idxStream);
2887 }
2888 }
2889
2890 /* Clear stream tags <-> objects mapping table. */
2891 RT_ZERO(pThisCC->aTags);
2892
2893 /* Emulation of codec "wake up" (HDA spec 5.5.1 and 6.5). */
2894 HDA_REG(pThis, STATESTS) = 0x1;
2895
2896 LogFlowFuncLeave();
2897 LogRel(("HDA: Reset\n"));
2898}
2899
2900#else /* !IN_RING3 */
2901
2902/**
2903 * Checks if a dword read starting with @a idxRegDsc is safe.
2904 *
2905 * We can guarentee it only standard reader callbacks are used.
2906 * @returns true if it will always succeed, false if it may return back to
2907 * ring-3 or we're just not sure.
2908 * @param idxRegDsc The first register descriptor in the DWORD being read.
2909 */
2910DECLINLINE(bool) hdaIsMultiReadSafeInRZ(unsigned idxRegDsc)
2911{
2912 int32_t cbLeft = 4; /* signed on purpose */
2913 do
2914 {
2915 if ( g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadU24
2916 || g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadU16
2917 || g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadU8
2918 || g_aHdaRegMap[idxRegDsc].pfnRead == hdaRegReadUnimpl)
2919 { /* okay */ }
2920 else
2921 {
2922 Log4(("hdaIsMultiReadSafeInRZ: idxRegDsc=%u %s\n", idxRegDsc, g_aHdaRegMap[idxRegDsc].abbrev));
2923 return false;
2924 }
2925
2926 idxRegDsc++;
2927 if (idxRegDsc < RT_ELEMENTS(g_aHdaRegMap))
2928 cbLeft -= g_aHdaRegMap[idxRegDsc].offset - g_aHdaRegMap[idxRegDsc - 1].offset;
2929 else
2930 break;
2931 } while (cbLeft > 0);
2932 return true;
2933}
2934
2935
2936#endif /* !IN_RING3 */
2937
2938
2939/* MMIO callbacks */
2940
2941/**
2942 * @callback_method_impl{FNIOMMMIONEWREAD, Looks up and calls the appropriate handler.}
2943 *
2944 * @note During implementation, we discovered so-called "forgotten" or "hole"
2945 * registers whose description is not listed in the RPM, datasheet, or
2946 * spec.
2947 */
2948static DECLCALLBACK(VBOXSTRICTRC) hdaMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
2949{
2950 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
2951 VBOXSTRICTRC rc;
2952 RT_NOREF_PV(pvUser);
2953 Assert(pThis->uAlignmentCheckMagic == HDASTATE_ALIGNMENT_CHECK_MAGIC);
2954
2955 /*
2956 * Look up and log.
2957 */
2958 int idxRegDsc = hdaRegLookup(off); /* Register descriptor index. */
2959#ifdef LOG_ENABLED
2960 unsigned const cbLog = cb;
2961 uint32_t offRegLog = (uint32_t)off;
2962#endif
2963
2964 Log3Func(("off=%#x cb=%#x\n", offRegLog, cb));
2965 Assert(cb == 4); Assert((off & 3) == 0);
2966
2967 rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VINF_IOM_R3_MMIO_READ);
2968 if (rc == VINF_SUCCESS)
2969 {
2970 if (!(HDA_REG(pThis, GCTL) & HDA_GCTL_CRST) && idxRegDsc != HDA_REG_GCTL)
2971 LogFunc(("Access to registers except GCTL is blocked while resetting\n"));
2972
2973 if (idxRegDsc >= 0)
2974 {
2975 /* ASSUMES gapless DWORD at end of map. */
2976 if (g_aHdaRegMap[idxRegDsc].size == 4)
2977 {
2978 /*
2979 * Straight forward DWORD access.
2980 */
2981 rc = g_aHdaRegMap[idxRegDsc].pfnRead(pDevIns, pThis, idxRegDsc, (uint32_t *)pv);
2982 Log3Func(("\tRead %s => %x (%Rrc)\n", g_aHdaRegMap[idxRegDsc].abbrev, *(uint32_t *)pv, VBOXSTRICTRC_VAL(rc)));
2983 STAM_COUNTER_INC(&pThis->aStatRegReads[idxRegDsc]);
2984 }
2985#ifndef IN_RING3
2986 else if (!hdaIsMultiReadSafeInRZ(idxRegDsc))
2987
2988 {
2989 STAM_COUNTER_INC(&pThis->aStatRegReadsToR3[idxRegDsc]);
2990 rc = VINF_IOM_R3_MMIO_READ;
2991 }
2992#endif
2993 else
2994 {
2995 /*
2996 * Multi register read (unless there are trailing gaps).
2997 * ASSUMES that only DWORD reads have sideeffects.
2998 */
2999 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegMultiReads));
3000 Log4(("hdaMmioRead: multi read: %#x LB %#x %s\n", off, cb, g_aHdaRegMap[idxRegDsc].abbrev));
3001 uint32_t u32Value = 0;
3002 unsigned cbLeft = 4;
3003 do
3004 {
3005 uint32_t const cbReg = g_aHdaRegMap[idxRegDsc].size;
3006 uint32_t u32Tmp = 0;
3007
3008 rc = g_aHdaRegMap[idxRegDsc].pfnRead(pDevIns, pThis, idxRegDsc, &u32Tmp);
3009 Log4Func(("\tRead %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxRegDsc].abbrev, cbReg, u32Tmp, VBOXSTRICTRC_VAL(rc)));
3010 STAM_COUNTER_INC(&pThis->aStatRegReads[idxRegDsc]);
3011#ifdef IN_RING3
3012 if (rc != VINF_SUCCESS)
3013 break;
3014#else
3015 AssertMsgBreak(rc == VINF_SUCCESS, ("rc=%Rrc - impossible, we sanitized the readers!\n", VBOXSTRICTRC_VAL(rc)));
3016#endif
3017 u32Value |= (u32Tmp & g_afMasks[cbReg]) << ((4 - cbLeft) * 8);
3018
3019 cbLeft -= cbReg;
3020 off += cbReg;
3021 idxRegDsc++;
3022 } while (cbLeft > 0 && g_aHdaRegMap[idxRegDsc].offset == off);
3023
3024 if (rc == VINF_SUCCESS)
3025 *(uint32_t *)pv = u32Value;
3026 else
3027 Assert(!IOM_SUCCESS(rc));
3028 }
3029 }
3030 else
3031 {
3032 LogRel(("HDA: Invalid read access @0x%x (bytes=%u)\n", (uint32_t)off, cb));
3033 Log3Func(("\tHole at %x is accessed for read\n", offRegLog));
3034 STAM_COUNTER_INC(&pThis->StatRegUnknownReads);
3035 rc = VINF_IOM_MMIO_UNUSED_FF;
3036 }
3037
3038 DEVHDA_UNLOCK(pDevIns, pThis);
3039
3040 /*
3041 * Log the outcome.
3042 */
3043#ifdef LOG_ENABLED
3044 if (cbLog == 4)
3045 Log3Func(("\tReturning @%#05x -> %#010x %Rrc\n", offRegLog, *(uint32_t *)pv, VBOXSTRICTRC_VAL(rc)));
3046 else if (cbLog == 2)
3047 Log3Func(("\tReturning @%#05x -> %#06x %Rrc\n", offRegLog, *(uint16_t *)pv, VBOXSTRICTRC_VAL(rc)));
3048 else if (cbLog == 1)
3049 Log3Func(("\tReturning @%#05x -> %#04x %Rrc\n", offRegLog, *(uint8_t *)pv, VBOXSTRICTRC_VAL(rc)));
3050#endif
3051 }
3052 else
3053 {
3054 if (idxRegDsc >= 0)
3055 STAM_COUNTER_INC(&pThis->aStatRegReadsToR3[idxRegDsc]);
3056 }
3057 return rc;
3058}
3059
3060
3061DECLINLINE(VBOXSTRICTRC) hdaWriteReg(PPDMDEVINS pDevIns, PHDASTATE pThis, int idxRegDsc, uint32_t u32Value, char const *pszLog)
3062{
3063 DEVHDA_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_MMIO_WRITE);
3064
3065 if (!(HDA_REG(pThis, GCTL) & HDA_GCTL_CRST) && idxRegDsc != HDA_REG_GCTL)
3066 {
3067 Log(("hdaWriteReg: Warning: Access to %s is blocked while controller is in reset mode\n", g_aHdaRegMap[idxRegDsc].abbrev));
3068 LogRel2(("HDA: Warning: Access to register %s is blocked while controller is in reset mode\n",
3069 g_aHdaRegMap[idxRegDsc].abbrev));
3070 STAM_COUNTER_INC(&pThis->StatRegWritesBlockedByReset);
3071
3072 DEVHDA_UNLOCK(pDevIns, pThis);
3073 return VINF_SUCCESS;
3074 }
3075
3076 /*
3077 * Handle RD (register description) flags.
3078 */
3079
3080 /* For SDI / SDO: Check if writes to those registers are allowed while SDCTL's RUN bit is set. */
3081 if (idxRegDsc >= HDA_NUM_GENERAL_REGS)
3082 {
3083 const uint32_t uSDCTL = HDA_STREAM_REG(pThis, CTL, HDA_SD_NUM_FROM_REG(pThis, CTL, idxRegDsc));
3084
3085 /*
3086 * Some OSes (like Win 10 AU) violate the spec by writing stuff to registers which are not supposed to be be touched
3087 * while SDCTL's RUN bit is set. So just ignore those values.
3088 */
3089
3090 /* Is the RUN bit currently set? */
3091 if ( RT_BOOL(uSDCTL & HDA_SDCTL_RUN)
3092 /* Are writes to the register denied if RUN bit is set? */
3093 && !(g_aHdaRegMap[idxRegDsc].fFlags & HDA_RD_F_SD_WRITE_RUN))
3094 {
3095 Log(("hdaWriteReg: Warning: Access to %s is blocked! %R[sdctl]\n", g_aHdaRegMap[idxRegDsc].abbrev, uSDCTL));
3096 LogRel2(("HDA: Warning: Access to register %s is blocked while the stream's RUN bit is set\n",
3097 g_aHdaRegMap[idxRegDsc].abbrev));
3098 STAM_COUNTER_INC(&pThis->StatRegWritesBlockedByRun);
3099
3100 DEVHDA_UNLOCK(pDevIns, pThis);
3101 return VINF_SUCCESS;
3102 }
3103 }
3104
3105#ifdef LOG_ENABLED
3106 uint32_t const idxRegMem = g_aHdaRegMap[idxRegDsc].mem_idx;
3107 uint32_t const u32OldValue = pThis->au32Regs[idxRegMem];
3108#endif
3109 VBOXSTRICTRC rc = g_aHdaRegMap[idxRegDsc].pfnWrite(pDevIns, pThis, idxRegDsc, u32Value);
3110 Log3Func(("Written value %#x to %s[%d byte]; %x => %x%s, rc=%d\n", u32Value, g_aHdaRegMap[idxRegDsc].abbrev,
3111 g_aHdaRegMap[idxRegDsc].size, u32OldValue, pThis->au32Regs[idxRegMem], pszLog, VBOXSTRICTRC_VAL(rc)));
3112#ifndef IN_RING3
3113 if (rc == VINF_IOM_R3_MMIO_WRITE)
3114 STAM_COUNTER_INC(&pThis->aStatRegWritesToR3[idxRegDsc]);
3115 else
3116#endif
3117 STAM_COUNTER_INC(&pThis->aStatRegWrites[idxRegDsc]);
3118
3119 DEVHDA_UNLOCK(pDevIns, pThis);
3120 RT_NOREF(pszLog);
3121 return rc;
3122}
3123
3124
3125/**
3126 * @callback_method_impl{FNIOMMMIONEWWRITE,
3127 * Looks up and calls the appropriate handler.}
3128 */
3129static DECLCALLBACK(VBOXSTRICTRC) hdaMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
3130{
3131 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3132 RT_NOREF_PV(pvUser);
3133 Assert(pThis->uAlignmentCheckMagic == HDASTATE_ALIGNMENT_CHECK_MAGIC);
3134
3135 /*
3136 * Look up and log the access.
3137 */
3138 int idxRegDsc = hdaRegLookup(off);
3139#if defined(IN_RING3) || defined(LOG_ENABLED)
3140 uint32_t idxRegMem = idxRegDsc != -1 ? g_aHdaRegMap[idxRegDsc].mem_idx : UINT32_MAX;
3141#endif
3142 uint64_t u64Value;
3143 if (cb == 4) u64Value = *(uint32_t const *)pv;
3144 else if (cb == 2) u64Value = *(uint16_t const *)pv;
3145 else if (cb == 1) u64Value = *(uint8_t const *)pv;
3146 else if (cb == 8) u64Value = *(uint64_t const *)pv;
3147 else
3148 ASSERT_GUEST_MSG_FAILED_RETURN(("cb=%u %.*Rhxs\n", cb, cb, pv),
3149 PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "odd write size: off=%RGp cb=%u\n", off, cb));
3150
3151 /*
3152 * The behavior of accesses that aren't aligned on natural boundraries is
3153 * undefined. Just reject them outright.
3154 */
3155 ASSERT_GUEST_MSG_RETURN((off & (cb - 1)) == 0, ("off=%RGp cb=%u %.*Rhxs\n", off, cb, cb, pv),
3156 PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "misaligned write access: off=%RGp cb=%u\n", off, cb));
3157
3158#ifdef LOG_ENABLED
3159 uint32_t const u32LogOldValue = idxRegDsc >= 0 ? pThis->au32Regs[idxRegMem] : UINT32_MAX;
3160#endif
3161
3162 /*
3163 * Try for a direct hit first.
3164 */
3165 VBOXSTRICTRC rc;
3166 if (idxRegDsc >= 0 && g_aHdaRegMap[idxRegDsc].size == cb)
3167 {
3168 Log3Func(("@%#05x u%u=%#0*RX64 %s\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, g_aHdaRegMap[idxRegDsc].abbrev));
3169 rc = hdaWriteReg(pDevIns, pThis, idxRegDsc, u64Value, "");
3170 Log3Func(("\t%#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
3171 }
3172 /*
3173 * Sub-register access. Supply missing bits as needed.
3174 */
3175 else if ( idxRegDsc >= 0
3176 && cb < g_aHdaRegMap[idxRegDsc].size)
3177 {
3178 u64Value |= pThis->au32Regs[g_aHdaRegMap[idxRegDsc].mem_idx]
3179 & g_afMasks[g_aHdaRegMap[idxRegDsc].size]
3180 & ~g_afMasks[cb];
3181 Log4Func(("@%#05x u%u=%#0*RX64 cb=%#x cbReg=%x %s\n"
3182 "\tSupplying missing bits (%#x): %#llx -> %#llx ...\n",
3183 (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, cb, g_aHdaRegMap[idxRegDsc].size, g_aHdaRegMap[idxRegDsc].abbrev,
3184 g_afMasks[g_aHdaRegMap[idxRegDsc].size] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
3185 rc = hdaWriteReg(pDevIns, pThis, idxRegDsc, u64Value, "");
3186 Log4Func(("\t%#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
3187 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegSubWrite));
3188 }
3189 /*
3190 * Partial or multiple register access, loop thru the requested memory.
3191 */
3192 else
3193 {
3194#ifdef IN_RING3
3195 if (idxRegDsc == -1)
3196 Log4Func(("@%#05x u32=%#010x cb=%d\n", (uint32_t)off, *(uint32_t const *)pv, cb));
3197 else if (g_aHdaRegMap[idxRegDsc].size == cb)
3198 Log4Func(("@%#05x u%u=%#0*RX64 %s\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value, g_aHdaRegMap[idxRegDsc].abbrev));
3199 else
3200 Log4Func(("@%#05x u%u=%#0*RX64 %s - mismatch cbReg=%u\n", (uint32_t)off, cb * 8, 2 + cb * 2, u64Value,
3201 g_aHdaRegMap[idxRegDsc].abbrev, g_aHdaRegMap[idxRegDsc].size));
3202
3203 /*
3204 * If it's an access beyond the start of the register, shift the input
3205 * value and fill in missing bits. Natural alignment rules means we
3206 * will only see 1 or 2 byte accesses of this kind, so no risk of
3207 * shifting out input values.
3208 */
3209 if (idxRegDsc < 0)
3210 {
3211 idxRegDsc = hdaR3RegLookupWithin(off);
3212 if (idxRegDsc != -1)
3213 {
3214 uint32_t const cbBefore = (uint32_t)off - g_aHdaRegMap[idxRegDsc].offset;
3215 Assert(cbBefore > 0 && cbBefore < 4);
3216 off -= cbBefore;
3217 idxRegMem = g_aHdaRegMap[idxRegDsc].mem_idx;
3218 u64Value <<= cbBefore * 8;
3219 u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbBefore];
3220 Log4Func(("\tWithin register, supplied %u leading bits: %#llx -> %#llx ...\n",
3221 cbBefore * 8, ~(uint64_t)g_afMasks[cbBefore] & u64Value, u64Value));
3222 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegMultiWrites));
3223 }
3224 else
3225 STAM_COUNTER_INC(&pThis->StatRegUnknownWrites);
3226 }
3227 else
3228 {
3229 Log4(("hdaMmioWrite: multi write: %s\n", g_aHdaRegMap[idxRegDsc].abbrev));
3230 STAM_COUNTER_INC(&pThis->CTX_SUFF_Z(StatRegMultiWrites));
3231 }
3232
3233 /* Loop thru the write area, it may cover multiple registers. */
3234 rc = VINF_SUCCESS;
3235 for (;;)
3236 {
3237 uint32_t cbReg;
3238 if (idxRegDsc >= 0)
3239 {
3240 idxRegMem = g_aHdaRegMap[idxRegDsc].mem_idx;
3241 cbReg = g_aHdaRegMap[idxRegDsc].size;
3242 if (cb < cbReg)
3243 {
3244 u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbReg] & ~g_afMasks[cb];
3245 Log4Func(("\tSupplying missing bits (%#x): %#llx -> %#llx ...\n",
3246 g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
3247 }
3248# ifdef LOG_ENABLED
3249 uint32_t uLogOldVal = pThis->au32Regs[idxRegMem];
3250# endif
3251 rc = hdaWriteReg(pDevIns, pThis, idxRegDsc, u64Value & g_afMasks[cbReg], "*");
3252 Log4Func(("\t%#x -> %#x\n", uLogOldVal, pThis->au32Regs[idxRegMem]));
3253 }
3254 else
3255 {
3256 LogRel(("HDA: Invalid write access @0x%x\n", (uint32_t)off));
3257 cbReg = 1;
3258 }
3259 if (rc != VINF_SUCCESS)
3260 break;
3261 if (cbReg >= cb)
3262 break;
3263
3264 /* Advance. */
3265 off += cbReg;
3266 cb -= cbReg;
3267 u64Value >>= cbReg * 8;
3268 if (idxRegDsc == -1)
3269 idxRegDsc = hdaRegLookup(off);
3270 else
3271 {
3272 idxRegDsc++;
3273 if ( (unsigned)idxRegDsc >= RT_ELEMENTS(g_aHdaRegMap)
3274 || g_aHdaRegMap[idxRegDsc].offset != off)
3275 idxRegDsc = -1;
3276 }
3277 }
3278
3279#else /* !IN_RING3 */
3280 /* Take the simple way out. */
3281 rc = VINF_IOM_R3_MMIO_WRITE;
3282#endif /* !IN_RING3 */
3283 }
3284
3285 return rc;
3286}
3287
3288#ifdef IN_RING3
3289
3290
3291/*********************************************************************************************************************************
3292* Saved state *
3293*********************************************************************************************************************************/
3294
3295/**
3296 * @callback_method_impl{FNSSMFIELDGETPUT,
3297 * Version 6 saves the IOC flag in HDABDLEDESC::fFlags as a bool}
3298 */
3299static DECLCALLBACK(int)
3300hdaR3GetPutTrans_HDABDLEDESC_fFlags_6(PSSMHANDLE pSSM, const struct SSMFIELD *pField, void *pvStruct,
3301 uint32_t fFlags, bool fGetOrPut, void *pvUser)
3302{
3303 PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
3304 RT_NOREF(pSSM, pField, pvStruct, fFlags);
3305 AssertReturn(fGetOrPut, VERR_INTERNAL_ERROR_4);
3306 bool fIoc;
3307 int rc = pDevIns->pHlpR3->pfnSSMGetBool(pSSM, &fIoc);
3308 if (RT_SUCCESS(rc))
3309 {
3310 PHDABDLEDESC pDesc = (PHDABDLEDESC)pvStruct;
3311 pDesc->fFlags = fIoc ? HDA_BDLE_F_IOC : 0;
3312 }
3313 return rc;
3314}
3315
3316
3317/**
3318 * @callback_method_impl{FNSSMFIELDGETPUT,
3319 * Versions 1 thru 4 save the IOC flag in HDASTREAMSTATE::DescfFlags as a bool}
3320 */
3321static DECLCALLBACK(int)
3322hdaR3GetPutTrans_HDABDLE_Desc_fFlags_1thru4(PSSMHANDLE pSSM, const struct SSMFIELD *pField, void *pvStruct,
3323 uint32_t fFlags, bool fGetOrPut, void *pvUser)
3324{
3325 PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
3326 RT_NOREF(pSSM, pField, pvStruct, fFlags);
3327 AssertReturn(fGetOrPut, VERR_INTERNAL_ERROR_4);
3328 bool fIoc;
3329 int rc = pDevIns->pHlpR3->pfnSSMGetBool(pSSM, &fIoc);
3330 if (RT_SUCCESS(rc))
3331 {
3332 PHDABDLE pState = (PHDABDLE)pvStruct;
3333 pState->Desc.fFlags = fIoc ? HDA_BDLE_F_IOC : 0;
3334 }
3335 return rc;
3336}
3337
3338
3339static int hdaR3SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)
3340{
3341 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3342# ifdef LOG_ENABLED
3343 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3344# endif
3345
3346 Log2Func(("[SD%RU8]\n", pStreamShared->u8SD));
3347
3348 /* Save stream ID. */
3349 Assert(pStreamShared->u8SD < HDA_MAX_STREAMS);
3350 int rc = pHlp->pfnSSMPutU8(pSSM, pStreamShared->u8SD);
3351 AssertRCReturn(rc, rc);
3352
3353 rc = pHlp->pfnSSMPutStructEx(pSSM, &pStreamShared->State, sizeof(pStreamShared->State),
3354 0 /*fFlags*/, g_aSSMStreamStateFields7, NULL);
3355 AssertRCReturn(rc, rc);
3356
3357 rc = pHlp->pfnSSMPutStructEx(pSSM, &pStreamShared->State.BDLE.Desc, sizeof(pStreamShared->State.BDLE.Desc),
3358 0 /*fFlags*/, g_aSSMBDLEDescFields7, NULL);
3359 AssertRCReturn(rc, rc);
3360
3361 rc = pHlp->pfnSSMPutStructEx(pSSM, &pStreamShared->State.BDLE.State, sizeof(pStreamShared->State.BDLE.State),
3362 0 /*fFlags*/, g_aSSMBDLEStateFields7, NULL);
3363 AssertRCReturn(rc, rc);
3364
3365 rc = pHlp->pfnSSMPutStructEx(pSSM, &pStreamShared->State.Period, sizeof(pStreamShared->State.Period),
3366 0 /* fFlags */, g_aSSMStreamPeriodFields7, NULL);
3367 AssertRCReturn(rc, rc);
3368
3369 uint32_t cbCircBufSize = 0;
3370 uint32_t cbCircBufUsed = 0;
3371
3372 if (pStreamR3->State.pCircBuf)
3373 {
3374 cbCircBufSize = (uint32_t)RTCircBufSize(pStreamR3->State.pCircBuf);
3375 cbCircBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
3376 }
3377
3378 rc = pHlp->pfnSSMPutU32(pSSM, cbCircBufSize);
3379 AssertRCReturn(rc, rc);
3380
3381 rc = pHlp->pfnSSMPutU32(pSSM, cbCircBufUsed);
3382 AssertRCReturn(rc, rc);
3383
3384 if (cbCircBufUsed)
3385 {
3386 /*
3387 * We now need to get the circular buffer's data without actually modifying
3388 * the internal read / used offsets -- otherwise we would end up with broken audio
3389 * data after saving the state.
3390 *
3391 * So get the current read offset and serialize the buffer data manually based on that.
3392 */
3393 size_t const offBuf = RTCircBufOffsetRead(pStreamR3->State.pCircBuf);
3394 void *pvBuf;
3395 size_t cbBuf;
3396 RTCircBufAcquireReadBlock(pStreamR3->State.pCircBuf, cbCircBufUsed, &pvBuf, &cbBuf);
3397 Assert(cbBuf);
3398 if (cbBuf)
3399 {
3400 rc = pHlp->pfnSSMPutMem(pSSM, pvBuf, cbBuf);
3401 AssertRC(rc);
3402 if ( RT_SUCCESS(rc)
3403 && cbBuf < cbCircBufUsed)
3404 {
3405 rc = pHlp->pfnSSMPutMem(pSSM, (uint8_t *)pvBuf - offBuf, cbCircBufUsed - cbBuf);
3406 }
3407 }
3408 RTCircBufReleaseReadBlock(pStreamR3->State.pCircBuf, 0 /* Don't advance read pointer -- see comment above */);
3409 }
3410
3411 Log2Func(("[SD%RU8] LPIB=%RU32, CBL=%RU32, LVI=%RU32\n", pStreamR3->u8SD, HDA_STREAM_REG(pThis, LPIB, pStreamShared->u8SD),
3412 HDA_STREAM_REG(pThis, CBL, pStreamShared->u8SD), HDA_STREAM_REG(pThis, LVI, pStreamShared->u8SD)));
3413
3414#ifdef LOG_ENABLED
3415 hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
3416#endif
3417
3418 return rc;
3419}
3420
3421/**
3422 * @callback_method_impl{FNSSMDEVSAVEEXEC}
3423 */
3424static DECLCALLBACK(int) hdaR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
3425{
3426 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3427 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
3428 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3429
3430 /* Save Codec nodes states. */
3431 hdaCodecSaveState(pDevIns, &pThis->Codec, pSSM);
3432
3433 /* Save MMIO registers. */
3434 pHlp->pfnSSMPutU32(pSSM, RT_ELEMENTS(pThis->au32Regs));
3435 pHlp->pfnSSMPutMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
3436
3437 /* Save controller-specifc internals. */
3438 pHlp->pfnSSMPutU64(pSSM, pThis->u64WalClk);
3439 pHlp->pfnSSMPutU8(pSSM, pThis->u8IRQL);
3440
3441 /* Save number of streams. */
3442 pHlp->pfnSSMPutU32(pSSM, HDA_MAX_STREAMS);
3443
3444 /* Save stream states. */
3445 for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
3446 {
3447 int rc = hdaR3SaveStream(pDevIns, pSSM, &pThis->aStreams[i], &pThisCC->aStreams[i]);
3448 AssertRCReturn(rc, rc);
3449 }
3450
3451 return VINF_SUCCESS;
3452}
3453
3454/**
3455 * Does required post processing when loading a saved state.
3456 *
3457 * @param pDevIns The device instance.
3458 * @param pThis Pointer to the shared HDA state.
3459 * @param pThisCC Pointer to the ring-3 HDA state.
3460 */
3461static int hdaR3LoadExecPost(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC)
3462{
3463 int rc = VINF_SUCCESS; /** @todo r=bird: Really, what's the point of this? */
3464
3465 /*
3466 * Enable all previously active streams.
3467 */
3468 for (size_t i = 0; i < HDA_MAX_STREAMS; i++)
3469 {
3470 PHDASTREAM pStreamShared = &pThis->aStreams[i];
3471
3472 bool fActive = RT_BOOL(HDA_STREAM_REG(pThis, CTL, i) & HDA_SDCTL_RUN);
3473 if (fActive)
3474 {
3475 PHDASTREAMR3 pStreamR3 = &pThisCC->aStreams[i];
3476
3477 int rc2;
3478#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
3479 /* Make sure to also create the async I/O thread before actually enabling the stream. */
3480 rc2 = hdaR3StreamAsyncIOCreate(pStreamR3);
3481 AssertRC(rc2);
3482
3483 /* ... and enabling it. */
3484 hdaR3StreamAsyncIOEnable(pStreamR3, true /* fEnable */);
3485#endif
3486 /* Resume the stream's period. */
3487 hdaR3StreamPeriodResume(&pStreamShared->State.Period);
3488
3489 /* (Re-)enable the stream. */
3490 rc2 = hdaR3StreamEnable(pStreamShared, pStreamR3, true /* fEnable */);
3491 AssertRC(rc2);
3492
3493 /* Add the stream to the device setup. */
3494 rc2 = hdaR3AddStream(pThisCC, &pStreamShared->State.Cfg);
3495 AssertRC(rc2);
3496
3497#ifdef HDA_USE_DMA_ACCESS_HANDLER
3498 /* (Re-)install the DMA handler. */
3499 hdaR3StreamRegisterDMAHandlers(pThis, pStreamShared);
3500#endif
3501 if (hdaR3StreamTransferIsScheduled(pStreamShared, PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer)))
3502 {
3503 /* Avoid going through the timer here by calling the stream's timer function directly.
3504 * Should speed up starting the stream transfers. */
3505 hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
3506 }
3507
3508 /* Also keep track of the currently active streams. */
3509 pThisCC->cStreamsActive++;
3510 }
3511 }
3512
3513 LogFlowFuncLeaveRC(rc);
3514 return rc;
3515}
3516
3517
3518/**
3519 * Handles loading of all saved state versions older than the current one.
3520 *
3521 * @param pDevIns The device instance.
3522 * @param pThis Pointer to the shared HDA state.
3523 * @param pThisCC Pointer to the ring-3 HDA state.
3524 * @param pSSM Pointer to SSM handle.
3525 * @param uVersion Saved state version to load.
3526 */
3527static int hdaR3LoadExecLegacy(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PSSMHANDLE pSSM, uint32_t uVersion)
3528{
3529 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3530 int rc;
3531
3532 /*
3533 * Load MMIO registers.
3534 */
3535 uint32_t cRegs;
3536 switch (uVersion)
3537 {
3538 case HDA_SAVED_STATE_VERSION_1:
3539 /* Starting with r71199, we would save 112 instead of 113
3540 registers due to some code cleanups. This only affected trunk
3541 builds in the 4.1 development period. */
3542 cRegs = 113;
3543 if (pHlp->pfnSSMHandleRevision(pSSM) >= 71199)
3544 {
3545 uint32_t uVer = pHlp->pfnSSMHandleVersion(pSSM);
3546 if ( VBOX_FULL_VERSION_GET_MAJOR(uVer) == 4
3547 && VBOX_FULL_VERSION_GET_MINOR(uVer) == 0
3548 && VBOX_FULL_VERSION_GET_BUILD(uVer) >= 51)
3549 cRegs = 112;
3550 }
3551 break;
3552
3553 case HDA_SAVED_STATE_VERSION_2:
3554 case HDA_SAVED_STATE_VERSION_3:
3555 cRegs = 112;
3556 AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= 112);
3557 break;
3558
3559 /* Since version 4 we store the register count to stay flexible. */
3560 case HDA_SAVED_STATE_VERSION_4:
3561 case HDA_SAVED_STATE_VERSION_5:
3562 case HDA_SAVED_STATE_VERSION_6:
3563 rc = pHlp->pfnSSMGetU32(pSSM, &cRegs);
3564 AssertRCReturn(rc, rc);
3565 if (cRegs != RT_ELEMENTS(pThis->au32Regs))
3566 LogRel(("HDA: SSM version cRegs is %RU32, expected %RU32\n", cRegs, RT_ELEMENTS(pThis->au32Regs)));
3567 break;
3568
3569 default:
3570 AssertLogRelMsgFailedReturn(("HDA: Internal Error! Didn't expect saved state version %RU32 ending up in hdaR3LoadExecLegacy!\n",
3571 uVersion), VERR_INTERNAL_ERROR_5);
3572 }
3573
3574 if (cRegs >= RT_ELEMENTS(pThis->au32Regs))
3575 {
3576 pHlp->pfnSSMGetMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
3577 pHlp->pfnSSMSkip(pSSM, sizeof(uint32_t) * (cRegs - RT_ELEMENTS(pThis->au32Regs)));
3578 }
3579 else
3580 pHlp->pfnSSMGetMem(pSSM, pThis->au32Regs, sizeof(uint32_t) * cRegs);
3581
3582 /* Make sure to update the base addresses first before initializing any streams down below. */
3583 pThis->u64CORBBase = RT_MAKE_U64(HDA_REG(pThis, CORBLBASE), HDA_REG(pThis, CORBUBASE));
3584 pThis->u64RIRBBase = RT_MAKE_U64(HDA_REG(pThis, RIRBLBASE), HDA_REG(pThis, RIRBUBASE));
3585 pThis->u64DPBase = RT_MAKE_U64(HDA_REG(pThis, DPLBASE) & DPBASE_ADDR_MASK, HDA_REG(pThis, DPUBASE));
3586
3587 /* Also make sure to update the DMA position bit if this was enabled when saving the state. */
3588 pThis->fDMAPosition = RT_BOOL(HDA_REG(pThis, DPLBASE) & RT_BIT_32(0));
3589
3590 /*
3591 * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
3592 *
3593 * Note: Saved states < v5 store LVI (u32BdleMaxCvi) for
3594 * *every* BDLE state, whereas it only needs to be stored
3595 * *once* for every stream. Most of the BDLE state we can
3596 * get out of the registers anyway, so just ignore those values.
3597 *
3598 * Also, only the current BDLE was saved, regardless whether
3599 * there were more than one (and there are at least two entries,
3600 * according to the spec).
3601 */
3602 switch (uVersion)
3603 {
3604 case HDA_SAVED_STATE_VERSION_1:
3605 case HDA_SAVED_STATE_VERSION_2:
3606 case HDA_SAVED_STATE_VERSION_3:
3607 case HDA_SAVED_STATE_VERSION_4:
3608 {
3609 /* Only load the internal states.
3610 * The rest will be initialized from the saved registers later. */
3611
3612 /* Note 1: Only the *current* BDLE for a stream was saved! */
3613 /* Note 2: The stream's saving order is/was fixed, so don't touch! */
3614
3615 /* Output */
3616 PHDASTREAM pStreamShared = &pThis->aStreams[4];
3617 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, &pThisCC->aStreams[4], 4 /* Stream descriptor, hardcoded */);
3618 AssertRCReturn(rc, rc);
3619 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE, sizeof(pStreamShared->State.BDLE),
3620 0 /* fFlags */, g_aSSMStreamBdleFields1234, pDevIns);
3621 AssertRCReturn(rc, rc);
3622 pStreamShared->State.uCurBDLE = pStreamShared->State.BDLE.State.u32BDLIndex;
3623
3624 /* Microphone-In */
3625 pStreamShared = &pThis->aStreams[2];
3626 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, &pThisCC->aStreams[2], 2 /* Stream descriptor, hardcoded */);
3627 AssertRCReturn(rc, rc);
3628 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE, sizeof(pStreamShared->State.BDLE),
3629 0 /* fFlags */, g_aSSMStreamBdleFields1234, pDevIns);
3630 AssertRCReturn(rc, rc);
3631 pStreamShared->State.uCurBDLE = pStreamShared->State.BDLE.State.u32BDLIndex;
3632
3633 /* Line-In */
3634 pStreamShared = &pThis->aStreams[0];
3635 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, &pThisCC->aStreams[0], 0 /* Stream descriptor, hardcoded */);
3636 AssertRCReturn(rc, rc);
3637 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE, sizeof(pStreamShared->State.BDLE),
3638 0 /* fFlags */, g_aSSMStreamBdleFields1234, pDevIns);
3639 AssertRCReturn(rc, rc);
3640 pStreamShared->State.uCurBDLE = pStreamShared->State.BDLE.State.u32BDLIndex;
3641 break;
3642 }
3643
3644 /*
3645 * v5 & v6 - Since v5 we support flexible stream and BDLE counts.
3646 */
3647 default:
3648 {
3649 /* Stream count. */
3650 uint32_t cStreams;
3651 rc = pHlp->pfnSSMGetU32(pSSM, &cStreams);
3652 AssertRCReturn(rc, rc);
3653 if (cStreams > HDA_MAX_STREAMS)
3654 return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
3655 N_("State contains %u streams while %u is the maximum supported"),
3656 cStreams, HDA_MAX_STREAMS);
3657
3658 /* Load stream states. */
3659 for (uint32_t i = 0; i < cStreams; i++)
3660 {
3661 uint8_t idStream;
3662 rc = pHlp->pfnSSMGetU8(pSSM, &idStream);
3663 AssertRCReturn(rc, rc);
3664
3665 HDASTREAM StreamDummyShared;
3666 HDASTREAMR3 StreamDummyR3;
3667 PHDASTREAM pStreamShared = idStream < RT_ELEMENTS(pThis->aStreams) ? &pThis->aStreams[idStream] : &StreamDummyShared;
3668 PHDASTREAMR3 pStreamR3 = idStream < RT_ELEMENTS(pThisCC->aStreams) ? &pThisCC->aStreams[idStream] : &StreamDummyR3;
3669 AssertLogRelMsgStmt(idStream < RT_ELEMENTS(pThisCC->aStreams),
3670 ("HDA stream ID=%RU8 not supported, skipping loadingit ...\n", idStream),
3671 RT_ZERO(StreamDummyShared); RT_ZERO(StreamDummyR3));
3672
3673 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, pStreamR3, idStream);
3674 if (RT_FAILURE(rc))
3675 {
3676 LogRel(("HDA: Stream #%RU32: Setting up of stream %RU8 failed, rc=%Rrc\n", i, idStream, rc));
3677 break;
3678 }
3679
3680 /*
3681 * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
3682 */
3683 if (uVersion == HDA_SAVED_STATE_VERSION_5)
3684 {
3685 struct V5HDASTREAMSTATE /* HDASTREAMSTATE + HDABDLE */
3686 {
3687 uint16_t cBLDEs;
3688 uint16_t uCurBDLE;
3689 uint32_t u32BDLEIndex;
3690 uint32_t cbBelowFIFOW;
3691 uint32_t u32BufOff;
3692 } Tmp;
3693 static SSMFIELD const g_aV5State1Fields[] =
3694 {
3695 SSMFIELD_ENTRY(V5HDASTREAMSTATE, cBLDEs),
3696 SSMFIELD_ENTRY(V5HDASTREAMSTATE, uCurBDLE),
3697 SSMFIELD_ENTRY_TERM()
3698 };
3699 rc = pHlp->pfnSSMGetStructEx(pSSM, &Tmp, sizeof(Tmp), 0 /* fFlags */, g_aV5State1Fields, NULL);
3700 AssertRCReturn(rc, rc);
3701 pStreamShared->State.uCurBDLE = Tmp.uCurBDLE;
3702
3703 for (uint16_t a = 0; a < Tmp.cBLDEs; a++)
3704 {
3705 static SSMFIELD const g_aV5State2Fields[] =
3706 {
3707 SSMFIELD_ENTRY(V5HDASTREAMSTATE, u32BDLEIndex),
3708 SSMFIELD_ENTRY_OLD(au8FIFO, 256),
3709 SSMFIELD_ENTRY(V5HDASTREAMSTATE, cbBelowFIFOW),
3710 SSMFIELD_ENTRY_TERM()
3711 };
3712 rc = pHlp->pfnSSMGetStructEx(pSSM, &Tmp, sizeof(Tmp), 0 /* fFlags */, g_aV5State2Fields, NULL);
3713 AssertRCReturn(rc, rc);
3714 if (Tmp.u32BDLEIndex == pStreamShared->State.uCurBDLE)
3715 {
3716 pStreamShared->State.BDLE.State.cbBelowFIFOW = Tmp.cbBelowFIFOW;
3717 pStreamShared->State.BDLE.State.u32BufOff = Tmp.u32BufOff;
3718 }
3719 }
3720 }
3721 else
3722 {
3723 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State, sizeof(HDASTREAMSTATE),
3724 0 /* fFlags */, g_aSSMStreamStateFields6, NULL);
3725 AssertRCReturn(rc, rc);
3726
3727 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE.Desc, sizeof(pStreamShared->State.BDLE.Desc),
3728 0 /* fFlags */, g_aSSMBDLEDescFields6, pDevIns);
3729 AssertRCReturn(rc, rc);
3730
3731 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE.State, sizeof(HDABDLESTATE),
3732 0 /* fFlags */, g_aSSMBDLEStateFields6, NULL);
3733 AssertRCReturn(rc, rc);
3734
3735 Log2Func(("[SD%RU8] LPIB=%RU32, CBL=%RU32, LVI=%RU32\n", idStream, HDA_STREAM_REG(pThis, LPIB, idStream),
3736 HDA_STREAM_REG(pThis, CBL, idStream), HDA_STREAM_REG(pThis, LVI, idStream)));
3737#ifdef LOG_ENABLED
3738 hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
3739#endif
3740 }
3741
3742 } /* for cStreams */
3743 break;
3744 } /* default */
3745 }
3746
3747 return rc;
3748}
3749
3750/**
3751 * @callback_method_impl{FNSSMDEVLOADEXEC}
3752 */
3753static DECLCALLBACK(int) hdaR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
3754{
3755 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
3756 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
3757 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3758
3759 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
3760
3761 LogRel2(("hdaR3LoadExec: uVersion=%RU32, uPass=0x%x\n", uVersion, uPass));
3762
3763 /*
3764 * Load Codec nodes states.
3765 */
3766 int rc = hdaR3CodecLoadState(pDevIns, &pThis->Codec, pThisCC->pCodec, pSSM, uVersion);
3767 if (RT_FAILURE(rc))
3768 {
3769 LogRel(("HDA: Failed loading codec state (version %RU32, pass 0x%x), rc=%Rrc\n", uVersion, uPass, rc));
3770 return rc;
3771 }
3772
3773 if (uVersion <= HDA_SAVED_STATE_VERSION_6) /* Handle older saved states? */
3774 {
3775 rc = hdaR3LoadExecLegacy(pDevIns, pThis, pThisCC, pSSM, uVersion);
3776 if (RT_SUCCESS(rc))
3777 rc = hdaR3LoadExecPost(pDevIns, pThis, pThisCC);
3778 return rc;
3779 }
3780
3781 /*
3782 * Load MMIO registers.
3783 */
3784 uint32_t cRegs;
3785 rc = pHlp->pfnSSMGetU32(pSSM, &cRegs); AssertRCReturn(rc, rc);
3786 AssertRCReturn(rc, rc);
3787 if (cRegs != RT_ELEMENTS(pThis->au32Regs))
3788 LogRel(("HDA: SSM version cRegs is %RU32, expected %RU32\n", cRegs, RT_ELEMENTS(pThis->au32Regs)));
3789
3790 if (cRegs >= RT_ELEMENTS(pThis->au32Regs))
3791 {
3792 pHlp->pfnSSMGetMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
3793 rc = pHlp->pfnSSMSkip(pSSM, sizeof(uint32_t) * (cRegs - RT_ELEMENTS(pThis->au32Regs)));
3794 AssertRCReturn(rc, rc);
3795 }
3796 else
3797 {
3798 rc = pHlp->pfnSSMGetMem(pSSM, pThis->au32Regs, sizeof(uint32_t) * cRegs);
3799 AssertRCReturn(rc, rc);
3800 }
3801
3802 /* Make sure to update the base addresses first before initializing any streams down below. */
3803 pThis->u64CORBBase = RT_MAKE_U64(HDA_REG(pThis, CORBLBASE), HDA_REG(pThis, CORBUBASE));
3804 pThis->u64RIRBBase = RT_MAKE_U64(HDA_REG(pThis, RIRBLBASE), HDA_REG(pThis, RIRBUBASE));
3805 pThis->u64DPBase = RT_MAKE_U64(HDA_REG(pThis, DPLBASE) & DPBASE_ADDR_MASK, HDA_REG(pThis, DPUBASE));
3806
3807 /* Also make sure to update the DMA position bit if this was enabled when saving the state. */
3808 pThis->fDMAPosition = RT_BOOL(HDA_REG(pThis, DPLBASE) & RT_BIT_32(0));
3809
3810 /*
3811 * Load controller-specifc internals.
3812 * Don't annoy other team mates (forgot this for state v7).
3813 */
3814 if ( pHlp->pfnSSMHandleRevision(pSSM) >= 116273
3815 || pHlp->pfnSSMHandleVersion(pSSM) >= VBOX_FULL_VERSION_MAKE(5, 2, 0))
3816 {
3817 pHlp->pfnSSMGetU64(pSSM, &pThis->u64WalClk);
3818 rc = pHlp->pfnSSMGetU8(pSSM, &pThis->u8IRQL);
3819 AssertRCReturn(rc, rc);
3820 }
3821
3822 /*
3823 * Load streams.
3824 */
3825 uint32_t cStreams;
3826 rc = pHlp->pfnSSMGetU32(pSSM, &cStreams);
3827 AssertRCReturn(rc, rc);
3828 if (cStreams > HDA_MAX_STREAMS)
3829 return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
3830 N_("State contains %u streams while %u is the maximum supported"),
3831 cStreams, HDA_MAX_STREAMS);
3832 Log2Func(("cStreams=%RU32\n", cStreams));
3833
3834 /* Load stream states. */
3835 for (uint32_t i = 0; i < cStreams; i++)
3836 {
3837 uint8_t idStream;
3838 rc = pHlp->pfnSSMGetU8(pSSM, &idStream);
3839 AssertRCReturn(rc, rc);
3840
3841 /* Paranoia. */
3842 AssertLogRelMsgReturn(idStream < HDA_MAX_STREAMS,
3843 ("HDA: Saved state contains bogus stream ID %RU8 for stream #%RU8", idStream, i),
3844 VERR_SSM_INVALID_STATE);
3845
3846 HDASTREAM StreamDummyShared;
3847 HDASTREAMR3 StreamDummyR3;
3848 PHDASTREAM pStreamShared = idStream < RT_ELEMENTS(pThis->aStreams) ? &pThis->aStreams[idStream] : &StreamDummyShared;
3849 PHDASTREAMR3 pStreamR3 = idStream < RT_ELEMENTS(pThisCC->aStreams) ? &pThisCC->aStreams[idStream] : &StreamDummyR3;
3850 AssertLogRelMsgStmt(idStream < RT_ELEMENTS(pThisCC->aStreams),
3851 ("HDA stream ID=%RU8 not supported, skipping loadingit ...\n", idStream),
3852 RT_ZERO(StreamDummyShared); RT_ZERO(StreamDummyR3));
3853
3854 rc = hdaR3StreamSetUp(pDevIns, pThis, pStreamShared, pStreamR3, idStream);
3855 if (RT_FAILURE(rc))
3856 {
3857 LogRel(("HDA: Stream #%RU8: Setting up failed, rc=%Rrc\n", idStream, rc));
3858 /* Continue. */
3859 }
3860
3861 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State, sizeof(HDASTREAMSTATE),
3862 0 /* fFlags */, g_aSSMStreamStateFields7, NULL);
3863 AssertRCReturn(rc, rc);
3864
3865 /*
3866 * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
3867 */
3868 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE.Desc, sizeof(HDABDLEDESC),
3869 0 /* fFlags */, g_aSSMBDLEDescFields7, NULL);
3870 AssertRCReturn(rc, rc);
3871
3872 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.BDLE.State, sizeof(HDABDLESTATE),
3873 0 /* fFlags */, g_aSSMBDLEStateFields7, NULL);
3874 AssertRCReturn(rc, rc);
3875
3876 Log2Func(("[SD%RU8] %R[bdle]\n", pStreamShared->u8SD, &pStreamShared->State.BDLE));
3877
3878 /*
3879 * Load period state.
3880 */
3881 hdaR3StreamPeriodInit(&pStreamShared->State.Period, pStreamShared->u8SD, pStreamShared->u16LVI,
3882 pStreamShared->u32CBL, &pStreamShared->State.Cfg);
3883
3884 rc = pHlp->pfnSSMGetStructEx(pSSM, &pStreamShared->State.Period, sizeof(pStreamShared->State.Period),
3885 0 /* fFlags */, g_aSSMStreamPeriodFields7, NULL);
3886 AssertRCReturn(rc, rc);
3887
3888 /*
3889 * Load internal (FIFO) buffer.
3890 */
3891 uint32_t cbCircBufSize = 0;
3892 pHlp->pfnSSMGetU32(pSSM, &cbCircBufSize); /* cbCircBuf */
3893 uint32_t cbCircBufUsed = 0;
3894 rc = pHlp->pfnSSMGetU32(pSSM, &cbCircBufUsed); /* cbCircBuf */
3895 AssertRCReturn(rc, rc);
3896
3897 if (cbCircBufSize) /* If 0, skip the buffer. */
3898 {
3899 /* Paranoia. */
3900 AssertLogRelMsgReturn(cbCircBufSize <= _32M,
3901 ("HDA: Saved state contains bogus DMA buffer size (%RU32) for stream #%RU8",
3902 cbCircBufSize, idStream),
3903 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
3904 AssertLogRelMsgReturn(cbCircBufUsed <= cbCircBufSize,
3905 ("HDA: Saved state contains invalid DMA buffer usage (%RU32/%RU32) for stream #%RU8",
3906 cbCircBufUsed, cbCircBufSize, idStream),
3907 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
3908
3909 /* Do we need to cre-create the circular buffer do fit the data size? */
3910 if ( pStreamR3->State.pCircBuf
3911 && cbCircBufSize != (uint32_t)RTCircBufSize(pStreamR3->State.pCircBuf))
3912 {
3913 RTCircBufDestroy(pStreamR3->State.pCircBuf);
3914 pStreamR3->State.pCircBuf = NULL;
3915 }
3916
3917 rc = RTCircBufCreate(&pStreamR3->State.pCircBuf, cbCircBufSize);
3918 AssertRCReturn(rc, rc);
3919
3920 if (cbCircBufUsed)
3921 {
3922 void *pvBuf;
3923 size_t cbBuf;
3924 RTCircBufAcquireWriteBlock(pStreamR3->State.pCircBuf, cbCircBufUsed, &pvBuf, &cbBuf);
3925
3926 AssertLogRelMsgReturn(cbBuf == cbCircBufUsed, ("cbBuf=%zu cbCircBufUsed=%zu\n", cbBuf, cbCircBufUsed),
3927 VERR_INTERNAL_ERROR_3);
3928 rc = pHlp->pfnSSMGetMem(pSSM, pvBuf, cbBuf);
3929 AssertRCReturn(rc, rc);
3930
3931 RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbBuf);
3932
3933 Assert(cbBuf == cbCircBufUsed);
3934 }
3935 }
3936
3937 Log2Func(("[SD%RU8] LPIB=%RU32, CBL=%RU32, LVI=%RU32\n", idStream, HDA_STREAM_REG(pThis, LPIB, idStream),
3938 HDA_STREAM_REG(pThis, CBL, idStream), HDA_STREAM_REG(pThis, LVI, idStream)));
3939#ifdef LOG_ENABLED
3940 hdaR3BDLEDumpAll(pDevIns, pThis, pStreamShared->u64BDLBase, pStreamShared->u16LVI + 1);
3941#endif
3942 /** @todo (Re-)initialize active periods? */
3943
3944 } /* for cStreams */
3945
3946 rc = hdaR3LoadExecPost(pDevIns, pThis, pThisCC);
3947 AssertRC(rc);
3948
3949 LogFlowFuncLeaveRC(rc);
3950 return rc;
3951}
3952
3953
3954/*********************************************************************************************************************************
3955* IPRT format type handlers *
3956*********************************************************************************************************************************/
3957
3958/**
3959 * @callback_method_impl{FNRTSTRFORMATTYPE}
3960 */
3961static DECLCALLBACK(size_t) hdaR3StrFmtBDLE(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
3962 const char *pszType, void const *pvValue,
3963 int cchWidth, int cchPrecision, unsigned fFlags,
3964 void *pvUser)
3965{
3966 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
3967 PHDABDLE pBDLE = (PHDABDLE)pvValue;
3968 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
3969 "BDLE(idx:%RU32, off:%RU32, fifow:%RU32, IOC:%RTbool, DMA[%RU32 bytes @ 0x%x])",
3970 pBDLE->State.u32BDLIndex, pBDLE->State.u32BufOff, pBDLE->State.cbBelowFIFOW,
3971 pBDLE->Desc.fFlags & HDA_BDLE_F_IOC, pBDLE->Desc.u32BufSize, pBDLE->Desc.u64BufAddr);
3972}
3973
3974/**
3975 * @callback_method_impl{FNRTSTRFORMATTYPE}
3976 */
3977static DECLCALLBACK(size_t) hdaR3StrFmtSDCTL(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
3978 const char *pszType, void const *pvValue,
3979 int cchWidth, int cchPrecision, unsigned fFlags,
3980 void *pvUser)
3981{
3982 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
3983 uint32_t uSDCTL = (uint32_t)(uintptr_t)pvValue;
3984 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
3985 "SDCTL(raw:%#x, DIR:%s, TP:%RTbool, STRIPE:%x, DEIE:%RTbool, FEIE:%RTbool, IOCE:%RTbool, RUN:%RTbool, RESET:%RTbool)",
3986 uSDCTL,
3987 uSDCTL & HDA_SDCTL_DIR ? "OUT" : "IN",
3988 RT_BOOL(uSDCTL & HDA_SDCTL_TP),
3989 (uSDCTL & HDA_SDCTL_STRIPE_MASK) >> HDA_SDCTL_STRIPE_SHIFT,
3990 RT_BOOL(uSDCTL & HDA_SDCTL_DEIE),
3991 RT_BOOL(uSDCTL & HDA_SDCTL_FEIE),
3992 RT_BOOL(uSDCTL & HDA_SDCTL_IOCE),
3993 RT_BOOL(uSDCTL & HDA_SDCTL_RUN),
3994 RT_BOOL(uSDCTL & HDA_SDCTL_SRST));
3995}
3996
3997/**
3998 * @callback_method_impl{FNRTSTRFORMATTYPE}
3999 */
4000static DECLCALLBACK(size_t) hdaR3StrFmtSDFIFOS(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
4001 const char *pszType, void const *pvValue,
4002 int cchWidth, int cchPrecision, unsigned fFlags,
4003 void *pvUser)
4004{
4005 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
4006 uint32_t uSDFIFOS = (uint32_t)(uintptr_t)pvValue;
4007 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOS(raw:%#x, sdfifos:%RU8 B)", uSDFIFOS, uSDFIFOS ? uSDFIFOS + 1 : 0);
4008}
4009
4010/**
4011 * @callback_method_impl{FNRTSTRFORMATTYPE}
4012 */
4013static DECLCALLBACK(size_t) hdaR3StrFmtSDFIFOW(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
4014 const char *pszType, void const *pvValue,
4015 int cchWidth, int cchPrecision, unsigned fFlags,
4016 void *pvUser)
4017{
4018 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
4019 uint32_t uSDFIFOW = (uint32_t)(uintptr_t)pvValue;
4020 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOW(raw: %#0x, sdfifow:%d B)", uSDFIFOW, hdaSDFIFOWToBytes(uSDFIFOW));
4021}
4022
4023/**
4024 * @callback_method_impl{FNRTSTRFORMATTYPE}
4025 */
4026static DECLCALLBACK(size_t) hdaR3StrFmtSDSTS(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
4027 const char *pszType, void const *pvValue,
4028 int cchWidth, int cchPrecision, unsigned fFlags,
4029 void *pvUser)
4030{
4031 RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
4032 uint32_t uSdSts = (uint32_t)(uintptr_t)pvValue;
4033 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
4034 "SDSTS(raw:%#0x, fifordy:%RTbool, dese:%RTbool, fifoe:%RTbool, bcis:%RTbool)",
4035 uSdSts,
4036 RT_BOOL(uSdSts & HDA_SDSTS_FIFORDY),
4037 RT_BOOL(uSdSts & HDA_SDSTS_DESE),
4038 RT_BOOL(uSdSts & HDA_SDSTS_FIFOE),
4039 RT_BOOL(uSdSts & HDA_SDSTS_BCIS));
4040}
4041
4042
4043/*********************************************************************************************************************************
4044* Debug Info Item Handlers *
4045*********************************************************************************************************************************/
4046
4047static int hdaR3DbgLookupRegByName(const char *pszArgs)
4048{
4049 int iReg = 0;
4050 for (; iReg < HDA_NUM_REGS; ++iReg)
4051 if (!RTStrICmp(g_aHdaRegMap[iReg].abbrev, pszArgs))
4052 return iReg;
4053 return -1;
4054}
4055
4056
4057static void hdaR3DbgPrintRegister(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaIndex)
4058{
4059 Assert( pThis
4060 && iHdaIndex >= 0
4061 && iHdaIndex < HDA_NUM_REGS);
4062 pHlp->pfnPrintf(pHlp, "%s: 0x%x\n", g_aHdaRegMap[iHdaIndex].abbrev, pThis->au32Regs[g_aHdaRegMap[iHdaIndex].mem_idx]);
4063}
4064
4065/**
4066 * @callback_method_impl{FNDBGFHANDLERDEV}
4067 */
4068static DECLCALLBACK(void) hdaR3DbgInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4069{
4070 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4071 int iHdaRegisterIndex = hdaR3DbgLookupRegByName(pszArgs);
4072 if (iHdaRegisterIndex != -1)
4073 hdaR3DbgPrintRegister(pThis, pHlp, iHdaRegisterIndex);
4074 else
4075 {
4076 for(iHdaRegisterIndex = 0; (unsigned int)iHdaRegisterIndex < HDA_NUM_REGS; ++iHdaRegisterIndex)
4077 hdaR3DbgPrintRegister(pThis, pHlp, iHdaRegisterIndex);
4078 }
4079}
4080
4081static void hdaR3DbgPrintStream(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iIdx)
4082{
4083 Assert( pThis
4084 && iIdx >= 0
4085 && iIdx < HDA_MAX_STREAMS);
4086
4087 const PHDASTREAM pStream = &pThis->aStreams[iIdx];
4088
4089 pHlp->pfnPrintf(pHlp, "Stream #%d:\n", iIdx);
4090 pHlp->pfnPrintf(pHlp, "\tSD%dCTL : %R[sdctl]\n", iIdx, HDA_STREAM_REG(pThis, CTL, iIdx));
4091 pHlp->pfnPrintf(pHlp, "\tSD%dCTS : %R[sdsts]\n", iIdx, HDA_STREAM_REG(pThis, STS, iIdx));
4092 pHlp->pfnPrintf(pHlp, "\tSD%dFIFOS: %R[sdfifos]\n", iIdx, HDA_STREAM_REG(pThis, FIFOS, iIdx));
4093 pHlp->pfnPrintf(pHlp, "\tSD%dFIFOW: %R[sdfifow]\n", iIdx, HDA_STREAM_REG(pThis, FIFOW, iIdx));
4094 pHlp->pfnPrintf(pHlp, "\tBDLE : %R[bdle]\n", &pStream->State.BDLE);
4095}
4096
4097static void hdaR3DbgPrintBDLE(PPDMDEVINS pDevIns, PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iIdx)
4098{
4099 Assert( pThis
4100 && iIdx >= 0
4101 && iIdx < HDA_MAX_STREAMS);
4102
4103 const PHDASTREAM pStream = &pThis->aStreams[iIdx];
4104 const PHDABDLE pBDLE = &pStream->State.BDLE;
4105
4106 pHlp->pfnPrintf(pHlp, "Stream #%d BDLE:\n", iIdx);
4107
4108 uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, iIdx),
4109 HDA_STREAM_REG(pThis, BDPU, iIdx));
4110 uint16_t u16LVI = HDA_STREAM_REG(pThis, LVI, iIdx);
4111 uint32_t u32CBL = HDA_STREAM_REG(pThis, CBL, iIdx);
4112
4113 if (!u64BaseDMA)
4114 return;
4115
4116 pHlp->pfnPrintf(pHlp, "\tCurrent: %R[bdle]\n\n", pBDLE);
4117
4118 pHlp->pfnPrintf(pHlp, "\tMemory:\n");
4119
4120 uint32_t cbBDLE = 0;
4121 for (uint16_t i = 0; i < u16LVI + 1; i++)
4122 {
4123 HDABDLEDESC bd;
4124 PDMDevHlpPhysRead(pDevIns, u64BaseDMA + i * sizeof(HDABDLEDESC), &bd, sizeof(bd));
4125
4126 pHlp->pfnPrintf(pHlp, "\t\t%s #%03d BDLE(adr:0x%llx, size:%RU32, ioc:%RTbool)\n",
4127 pBDLE->State.u32BDLIndex == i ? "*" : " ", i, bd.u64BufAddr, bd.u32BufSize, bd.fFlags & HDA_BDLE_F_IOC);
4128
4129 cbBDLE += bd.u32BufSize;
4130 }
4131
4132 pHlp->pfnPrintf(pHlp, "Total: %RU32 bytes\n", cbBDLE);
4133
4134 if (cbBDLE != u32CBL)
4135 pHlp->pfnPrintf(pHlp, "Warning: %RU32 bytes does not match CBL (%RU32)!\n", cbBDLE, u32CBL);
4136
4137 pHlp->pfnPrintf(pHlp, "DMA counters (base @ 0x%llx):\n", u64BaseDMA);
4138 if (!u64BaseDMA) /* No DMA base given? Bail out. */
4139 {
4140 pHlp->pfnPrintf(pHlp, "\tNo counters found\n");
4141 return;
4142 }
4143
4144 for (int i = 0; i < u16LVI + 1; i++)
4145 {
4146 uint32_t uDMACnt;
4147 PDMDevHlpPhysRead(pDevIns, (pThis->u64DPBase & DPBASE_ADDR_MASK) + (i * 2 * sizeof(uint32_t)),
4148 &uDMACnt, sizeof(uDMACnt));
4149
4150 pHlp->pfnPrintf(pHlp, "\t#%03d DMA @ 0x%x\n", i , uDMACnt);
4151 }
4152}
4153
4154static int hdaR3DbgLookupStrmIdx(PHDASTATE pThis, const char *pszArgs)
4155{
4156 RT_NOREF(pThis, pszArgs);
4157 /** @todo Add args parsing. */
4158 return -1;
4159}
4160
4161/**
4162 * @callback_method_impl{FNDBGFHANDLERDEV, hdastream}
4163 */
4164static DECLCALLBACK(void) hdaR3DbgInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4165{
4166 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4167 int iHdaStreamdex = hdaR3DbgLookupStrmIdx(pThis, pszArgs);
4168 if (iHdaStreamdex != -1)
4169 hdaR3DbgPrintStream(pThis, pHlp, iHdaStreamdex);
4170 else
4171 for(iHdaStreamdex = 0; iHdaStreamdex < HDA_MAX_STREAMS; ++iHdaStreamdex)
4172 hdaR3DbgPrintStream(pThis, pHlp, iHdaStreamdex);
4173}
4174
4175/**
4176 * @callback_method_impl{FNDBGFHANDLERDEV, hdabdle}
4177 */
4178static DECLCALLBACK(void) hdaR3DbgInfoBDLE(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4179{
4180 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4181 int iHdaStreamdex = hdaR3DbgLookupStrmIdx(pThis, pszArgs);
4182 if (iHdaStreamdex != -1)
4183 hdaR3DbgPrintBDLE(pDevIns, pThis, pHlp, iHdaStreamdex);
4184 else
4185 for (iHdaStreamdex = 0; iHdaStreamdex < HDA_MAX_STREAMS; ++iHdaStreamdex)
4186 hdaR3DbgPrintBDLE(pDevIns, pThis, pHlp, iHdaStreamdex);
4187}
4188
4189/**
4190 * @callback_method_impl{FNDBGFHANDLERDEV, hdcnodes}
4191 */
4192static DECLCALLBACK(void) hdaR3DbgInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4193{
4194 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4195 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4196
4197 if (pThisCC->pCodec->pfnDbgListNodes)
4198 pThisCC->pCodec->pfnDbgListNodes(&pThis->Codec, pThisCC->pCodec, pHlp, pszArgs);
4199 else
4200 pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
4201}
4202
4203/**
4204 * @callback_method_impl{FNDBGFHANDLERDEV, hdcselector}
4205 */
4206static DECLCALLBACK(void) hdaR3DbgInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4207{
4208 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4209 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4210
4211 if (pThisCC->pCodec->pfnDbgSelector)
4212 pThisCC->pCodec->pfnDbgSelector(&pThis->Codec, pThisCC->pCodec, pHlp, pszArgs);
4213 else
4214 pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
4215}
4216
4217/**
4218 * @callback_method_impl{FNDBGFHANDLERDEV, hdamixer}
4219 */
4220static DECLCALLBACK(void) hdaR3DbgInfoMixer(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4221{
4222 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4223
4224 if (pThisCC->pMixer)
4225 AudioMixerDebug(pThisCC->pMixer, pHlp, pszArgs);
4226 else
4227 pHlp->pfnPrintf(pHlp, "Mixer not available\n");
4228}
4229
4230
4231/*********************************************************************************************************************************
4232* PDMIBASE *
4233*********************************************************************************************************************************/
4234
4235/**
4236 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4237 */
4238static DECLCALLBACK(void *) hdaR3QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
4239{
4240 PHDASTATER3 pThisCC = RT_FROM_MEMBER(pInterface, HDASTATER3, IBase);
4241
4242 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
4243 return NULL;
4244}
4245
4246
4247/*********************************************************************************************************************************
4248* PDMDEVREGR3 *
4249*********************************************************************************************************************************/
4250
4251/**
4252 * Attach command, internal version.
4253 *
4254 * This is called to let the device attach to a driver for a specified LUN
4255 * during runtime. This is not called during VM construction, the device
4256 * constructor has to attach to all the available drivers.
4257 *
4258 * @returns VBox status code.
4259 * @param pDevIns The device instance.
4260 * @param pThis The shared HDA device state.
4261 * @param pThisCC The ring-3 HDA device state.
4262 * @param uLUN The logical unit which is being detached.
4263 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
4264 * @param ppDrv Attached driver instance on success. Optional.
4265 */
4266static int hdaR3AttachInternal(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, unsigned uLUN, uint32_t fFlags, PHDADRIVER *ppDrv)
4267{
4268 RT_NOREF(fFlags);
4269
4270 /*
4271 * Attach driver.
4272 */
4273 char *pszDesc;
4274 if (RTStrAPrintf(&pszDesc, "Audio driver port (HDA) for LUN#%u", uLUN) <= 0)
4275 AssertLogRelFailedReturn(VERR_NO_MEMORY);
4276
4277 PPDMIBASE pDrvBase;
4278 int rc = PDMDevHlpDriverAttach(pDevIns, uLUN, &pThisCC->IBase, &pDrvBase, pszDesc);
4279 if (RT_SUCCESS(rc))
4280 {
4281 PHDADRIVER pDrv = (PHDADRIVER)RTMemAllocZ(sizeof(HDADRIVER));
4282 if (pDrv)
4283 {
4284 pDrv->pDrvBase = pDrvBase;
4285 pDrv->pHDAStateShared = pThis;
4286 pDrv->pHDAStateR3 = pThisCC;
4287 pDrv->uLUN = uLUN;
4288 pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
4289 AssertMsg(pDrv->pConnector != NULL, ("Configuration error: LUN#%u has no host audio interface, rc=%Rrc\n", uLUN, rc));
4290
4291 /*
4292 * For now we always set the driver at LUN 0 as our primary
4293 * host backend. This might change in the future.
4294 */
4295 if (pDrv->uLUN == 0)
4296 pDrv->fFlags |= PDMAUDIODRVFLAGS_PRIMARY;
4297
4298 LogFunc(("LUN#%u: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->fFlags));
4299
4300 /* Attach to driver list if not attached yet. */
4301 if (!pDrv->fAttached)
4302 {
4303 RTListAppend(&pThisCC->lstDrv, &pDrv->Node);
4304 pDrv->fAttached = true;
4305 }
4306
4307 if (ppDrv)
4308 *ppDrv = pDrv;
4309 }
4310 else
4311 rc = VERR_NO_MEMORY;
4312 }
4313 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4314 LogFunc(("No attached driver for LUN #%u\n", uLUN));
4315
4316 if (RT_FAILURE(rc))
4317 {
4318 /* Only free this string on failure;
4319 * must remain valid for the live of the driver instance. */
4320 RTStrFree(pszDesc);
4321 }
4322
4323 LogFunc(("uLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
4324 return rc;
4325}
4326
4327/**
4328 * Detach command, internal version.
4329 *
4330 * This is called to let the device detach from a driver for a specified LUN
4331 * during runtime.
4332 *
4333 * @returns VBox status code.
4334 * @param pThisCC The ring-3 HDA device state.
4335 * @param pDrv Driver to detach from device.
4336 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
4337 */
4338static int hdaR3DetachInternal(PHDASTATER3 pThisCC, PHDADRIVER pDrv, uint32_t fFlags)
4339{
4340 RT_NOREF(fFlags);
4341
4342 /* First, remove the driver from our list and destory it's associated streams.
4343 * This also will un-set the driver as a recording source (if associated). */
4344 hdaR3MixerRemoveDrv(pThisCC, pDrv);
4345
4346 /* Next, search backwards for a capable (attached) driver which now will be the
4347 * new recording source. */
4348 PHDADRIVER pDrvCur;
4349 RTListForEachReverse(&pThisCC->lstDrv, pDrvCur, HDADRIVER, Node)
4350 {
4351 if (!pDrvCur->pConnector)
4352 continue;
4353
4354 PDMAUDIOBACKENDCFG Cfg;
4355 int rc2 = pDrvCur->pConnector->pfnGetConfig(pDrvCur->pConnector, &Cfg);
4356 if (RT_FAILURE(rc2))
4357 continue;
4358
4359 PHDADRIVERSTREAM pDrvStrm;
4360# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
4361 pDrvStrm = &pDrvCur->MicIn;
4362 if ( pDrvStrm
4363 && pDrvStrm->pMixStrm)
4364 {
4365 rc2 = AudioMixerSinkSetRecordingSource(pThisCC->SinkMicIn.pMixSink, pDrvStrm->pMixStrm);
4366 if (RT_SUCCESS(rc2))
4367 LogRel2(("HDA: Set new recording source for 'Mic In' to '%s'\n", Cfg.szName));
4368 }
4369# endif
4370 pDrvStrm = &pDrvCur->LineIn;
4371 if ( pDrvStrm
4372 && pDrvStrm->pMixStrm)
4373 {
4374 rc2 = AudioMixerSinkSetRecordingSource(pThisCC->SinkLineIn.pMixSink, pDrvStrm->pMixStrm);
4375 if (RT_SUCCESS(rc2))
4376 LogRel2(("HDA: Set new recording source for 'Line In' to '%s'\n", Cfg.szName));
4377 }
4378 }
4379
4380 LogFunc(("uLUN=%u, fFlags=0x%x\n", pDrv->uLUN, fFlags));
4381 return VINF_SUCCESS;
4382}
4383
4384/**
4385 * @interface_method_impl{PDMDEVREG,pfnAttach}
4386 */
4387static DECLCALLBACK(int) hdaR3Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
4388{
4389 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4390 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4391
4392 DEVHDA_LOCK_RETURN(pDevIns, pThis, VERR_IGNORED);
4393
4394 LogFunc(("uLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
4395
4396 PHDADRIVER pDrv;
4397 int rc2 = hdaR3AttachInternal(pDevIns, pThis, pThisCC, uLUN, fFlags, &pDrv);
4398 if (RT_SUCCESS(rc2))
4399 rc2 = hdaR3MixerAddDrv(pThisCC, pDrv);
4400
4401 if (RT_FAILURE(rc2))
4402 LogFunc(("Failed with %Rrc\n", rc2));
4403
4404 DEVHDA_UNLOCK(pDevIns, pThis);
4405
4406 return VINF_SUCCESS;
4407}
4408
4409/**
4410 * @interface_method_impl{PDMDEVREG,pfnDetach}
4411 */
4412static DECLCALLBACK(void) hdaR3Detach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
4413{
4414 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4415 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4416
4417 DEVHDA_LOCK(pDevIns, pThis);
4418
4419 LogFunc(("uLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
4420
4421 PHDADRIVER pDrv, pDrvNext;
4422 RTListForEachSafe(&pThisCC->lstDrv, pDrv, pDrvNext, HDADRIVER, Node)
4423 {
4424 if (pDrv->uLUN == uLUN)
4425 {
4426 int rc2 = hdaR3DetachInternal(pThisCC, pDrv, fFlags);
4427 if (RT_SUCCESS(rc2))
4428 {
4429 RTMemFree(pDrv);
4430 pDrv = NULL;
4431 }
4432
4433 break;
4434 }
4435 }
4436
4437 DEVHDA_UNLOCK(pDevIns, pThis);
4438}
4439
4440/**
4441 * Powers off the device.
4442 *
4443 * @param pDevIns Device instance to power off.
4444 */
4445static DECLCALLBACK(void) hdaR3PowerOff(PPDMDEVINS pDevIns)
4446{
4447 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4448 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4449
4450 DEVHDA_LOCK_RETURN_VOID(pDevIns, pThis);
4451
4452 LogRel2(("HDA: Powering off ...\n"));
4453
4454 /* Ditto goes for the codec, which in turn uses the mixer. */
4455 hdaR3CodecPowerOff(pThisCC->pCodec);
4456
4457 /*
4458 * Note: Destroy the mixer while powering off and *not* in hdaR3Destruct,
4459 * giving the mixer the chance to release any references held to
4460 * PDM audio streams it maintains.
4461 */
4462 if (pThisCC->pMixer)
4463 {
4464 AudioMixerDestroy(pThisCC->pMixer);
4465 pThisCC->pMixer = NULL;
4466 }
4467
4468 DEVHDA_UNLOCK(pDevIns, pThis);
4469}
4470
4471/**
4472 * Replaces a driver with a the NullAudio drivers.
4473 *
4474 * @returns VBox status code.
4475 * @param pDevIns The device instance.
4476 * @param pThis The shared HDA device state.
4477 * @param pThisCC The ring-3 HDA device state.
4478 * @param iLun The logical unit which is being replaced.
4479 */
4480static int hdaR3ReconfigLunWithNullAudio(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, unsigned iLun)
4481{
4482 int rc = PDMDevHlpDriverReconfigure2(pDevIns, iLun, "AUDIO", "NullAudio");
4483 if (RT_SUCCESS(rc))
4484 rc = hdaR3AttachInternal(pDevIns, pThis, pThisCC, iLun, 0 /* fFlags */, NULL /* ppDrv */);
4485 LogFunc(("pThis=%p, iLun=%u, rc=%Rrc\n", pThis, iLun, rc));
4486 return rc;
4487}
4488
4489
4490/**
4491 * @interface_method_impl{PDMDEVREG,pfnReset}
4492 */
4493static DECLCALLBACK(void) hdaR3Reset(PPDMDEVINS pDevIns)
4494{
4495 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4496 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4497
4498 LogFlowFuncEnter();
4499
4500 DEVHDA_LOCK_RETURN_VOID(pDevIns, pThis);
4501
4502 /*
4503 * 18.2.6,7 defines that values of this registers might be cleared on power on/reset
4504 * hdaR3Reset shouldn't affects these registers.
4505 */
4506 HDA_REG(pThis, WAKEEN) = 0x0;
4507
4508 hdaR3GCTLReset(pDevIns, pThis, pThisCC);
4509
4510 /* Indicate that HDA is not in reset. The firmware is supposed to (un)reset HDA,
4511 * but we can take a shortcut.
4512 */
4513 HDA_REG(pThis, GCTL) = HDA_GCTL_CRST;
4514
4515 DEVHDA_UNLOCK(pDevIns, pThis);
4516}
4517
4518
4519/**
4520 * @interface_method_impl{PDMDEVREG,pfnDestruct}
4521 */
4522static DECLCALLBACK(int) hdaR3Destruct(PPDMDEVINS pDevIns)
4523{
4524 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); /* this shall come first */
4525 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4526 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4527 DEVHDA_LOCK(pDevIns, pThis); /** @todo r=bird: this will fail on early constructor failure. */
4528
4529 PHDADRIVER pDrv;
4530 while (!RTListIsEmpty(&pThisCC->lstDrv))
4531 {
4532 pDrv = RTListGetFirst(&pThisCC->lstDrv, HDADRIVER, Node);
4533
4534 RTListNodeRemove(&pDrv->Node);
4535 RTMemFree(pDrv);
4536 }
4537
4538 if (pThisCC->pCodec)
4539 {
4540 RTMemFree(pThisCC->pCodec);
4541 pThisCC->pCodec = NULL;
4542 }
4543
4544 hdaCodecDestruct(&pThis->Codec);
4545
4546 for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
4547 hdaR3StreamDestroy(&pThis->aStreams[i], &pThisCC->aStreams[i]);
4548
4549 DEVHDA_UNLOCK(pDevIns, pThis);
4550 return VINF_SUCCESS;
4551}
4552
4553
4554/**
4555 * @interface_method_impl{PDMDEVREG,pfnConstruct}
4556 */
4557static DECLCALLBACK(int) hdaR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
4558{
4559 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* this shall come first */
4560 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
4561 PHDASTATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER3);
4562 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4563 Assert(iInstance == 0); RT_NOREF(iInstance);
4564
4565 /*
4566 * Initialize the state sufficently to make the destructor work.
4567 */
4568 pThis->uAlignmentCheckMagic = HDASTATE_ALIGNMENT_CHECK_MAGIC;
4569 RTListInit(&pThisCC->lstDrv);
4570 pThis->cbCorbBuf = HDA_CORB_SIZE * HDA_CORB_ELEMENT_SIZE;
4571 pThis->cbRirbBuf = HDA_RIRB_SIZE * HDA_RIRB_ELEMENT_SIZE;
4572
4573 /** @todo r=bird: There are probably other things which should be
4574 * initialized here before we start failing. */
4575
4576 /*
4577 * Validate and read configuration.
4578 */
4579 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "BufSizeInMs|BufSizeOutMs|TimerHz|PosAdjustEnabled|PosAdjustFrames|TransferHeuristicsEnabled|DebugEnabled|DebugPathOut", "");
4580
4581 /* Note: Error checking of this value happens in hdaR3StreamSetUp(). */
4582 int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeInMs", &pThis->cbCircBufInMs, 0 /* Default value, if not set. */);
4583 if (RT_FAILURE(rc))
4584 return PDMDEV_SET_ERROR(pDevIns, rc,
4585 N_("HDA configuration error: failed to read input buffer size (ms) as unsigned integer"));
4586
4587 /* Note: Error checking of this value happens in hdaR3StreamSetUp(). */
4588 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeOutMs", &pThis->cbCircBufOutMs, 0 /* Default value, if not set. */);
4589 if (RT_FAILURE(rc))
4590 return PDMDEV_SET_ERROR(pDevIns, rc,
4591 N_("HDA configuration error: failed to read output buffer size (ms) as unsigned integer"));
4592
4593 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "TimerHz", &pThis->uTimerHz, HDA_TIMER_HZ_DEFAULT /* Default value, if not set. */);
4594 if (RT_FAILURE(rc))
4595 return PDMDEV_SET_ERROR(pDevIns, rc,
4596 N_("HDA configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
4597
4598 if (pThis->uTimerHz != HDA_TIMER_HZ_DEFAULT)
4599 LogRel(("HDA: Using custom device timer rate (%RU16Hz)\n", pThis->uTimerHz));
4600
4601 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "PosAdjustEnabled", &pThis->fPosAdjustEnabled, true);
4602 if (RT_FAILURE(rc))
4603 return PDMDEV_SET_ERROR(pDevIns, rc,
4604 N_("HDA configuration error: failed to read position adjustment enabled as boolean"));
4605
4606 if (!pThis->fPosAdjustEnabled)
4607 LogRel(("HDA: Position adjustment is disabled\n"));
4608
4609 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "PosAdjustFrames", &pThis->cPosAdjustFrames, HDA_POS_ADJUST_DEFAULT);
4610 if (RT_FAILURE(rc))
4611 return PDMDEV_SET_ERROR(pDevIns, rc,
4612 N_("HDA configuration error: failed to read position adjustment frames as unsigned integer"));
4613
4614 if (pThis->cPosAdjustFrames)
4615 LogRel(("HDA: Using custom position adjustment (%RU16 audio frames)\n", pThis->cPosAdjustFrames));
4616
4617 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "TransferHeuristicsEnabled", &pThis->fTransferHeuristicsEnabled, true);
4618 if (RT_FAILURE(rc))
4619 return PDMDEV_SET_ERROR(pDevIns, rc,
4620 N_("HDA configuration error: failed to read data transfer heuristics enabled as boolean"));
4621
4622 if (!pThis->fTransferHeuristicsEnabled)
4623 LogRel(("HDA: Data transfer heuristics are disabled\n"));
4624
4625 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DebugEnabled", &pThisCC->Dbg.fEnabled, false);
4626 if (RT_FAILURE(rc))
4627 return PDMDEV_SET_ERROR(pDevIns, rc,
4628 N_("HDA configuration error: failed to read debugging enabled flag as boolean"));
4629
4630 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "DebugPathOut", &pThisCC->Dbg.pszOutPath, NULL);
4631 if (RT_FAILURE(rc))
4632 return PDMDEV_SET_ERROR(pDevIns, rc,
4633 N_("HDA configuration error: failed to read debugging output path flag as string"));
4634
4635 if (pThisCC->Dbg.fEnabled)
4636 LogRel2(("HDA: Debug output will be saved to '%s'\n", pThisCC->Dbg.pszOutPath));
4637
4638 /*
4639 * Use our own critical section for the device instead of the default
4640 * one provided by PDM. This allows fine-grained locking in combination
4641 * with TM when timer-specific stuff is being called in e.g. the MMIO handlers.
4642 */
4643 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "HDA");
4644 AssertRCReturn(rc, rc);
4645
4646 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
4647 AssertRCReturn(rc, rc);
4648
4649 /*
4650 * Initialize data (most of it anyway).
4651 */
4652 pThisCC->pDevIns = pDevIns;
4653 /* IBase */
4654 pThisCC->IBase.pfnQueryInterface = hdaR3QueryInterface;
4655
4656 /* PCI Device */
4657 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
4658 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
4659
4660 PDMPciDevSetVendorId( pPciDev, HDA_PCI_VENDOR_ID); /* nVidia */
4661 PDMPciDevSetDeviceId( pPciDev, HDA_PCI_DEVICE_ID); /* HDA */
4662
4663 PDMPciDevSetCommand( pPciDev, 0x0000); /* 04 rw,ro - pcicmd. */
4664 PDMPciDevSetStatus( pPciDev, VBOX_PCI_STATUS_CAP_LIST); /* 06 rwc?,ro? - pcists. */
4665 PDMPciDevSetRevisionId( pPciDev, 0x01); /* 08 ro - rid. */
4666 PDMPciDevSetClassProg( pPciDev, 0x00); /* 09 ro - pi. */
4667 PDMPciDevSetClassSub( pPciDev, 0x03); /* 0a ro - scc; 03 == HDA. */
4668 PDMPciDevSetClassBase( pPciDev, 0x04); /* 0b ro - bcc; 04 == multimedia. */
4669 PDMPciDevSetHeaderType( pPciDev, 0x00); /* 0e ro - headtyp. */
4670 PDMPciDevSetBaseAddress( pPciDev, 0, /* 10 rw - MMIO */
4671 false /* fIoSpace */, false /* fPrefetchable */, true /* f64Bit */, 0x00000000);
4672 PDMPciDevSetInterruptLine( pPciDev, 0x00); /* 3c rw. */
4673 PDMPciDevSetInterruptPin( pPciDev, 0x01); /* 3d ro - INTA#. */
4674
4675# if defined(HDA_AS_PCI_EXPRESS)
4676 PDMPciDevSetCapabilityList(pPciDev, 0x80);
4677# elif defined(VBOX_WITH_MSI_DEVICES)
4678 PDMPciDevSetCapabilityList(pPciDev, 0x60);
4679# else
4680 PDMPciDevSetCapabilityList(pPciDev, 0x50); /* ICH6 datasheet 18.1.16 */
4681# endif
4682
4683 /// @todo r=michaln: If there are really no PDMPciDevSetXx for these, the
4684 /// meaning of these values needs to be properly documented!
4685 /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
4686 PDMPciDevSetByte( pPciDev, 0x40, 0x01);
4687
4688 /* Power Management */
4689 PDMPciDevSetByte( pPciDev, 0x50 + 0, VBOX_PCI_CAP_ID_PM);
4690 PDMPciDevSetByte( pPciDev, 0x50 + 1, 0x0); /* next */
4691 PDMPciDevSetWord( pPciDev, 0x50 + 2, VBOX_PCI_PM_CAP_DSI | 0x02 /* version, PM1.1 */ );
4692
4693# ifdef HDA_AS_PCI_EXPRESS
4694 /* PCI Express */
4695 PDMPciDevSetByte( pPciDev, 0x80 + 0, VBOX_PCI_CAP_ID_EXP); /* PCI_Express */
4696 PDMPciDevSetByte( pPciDev, 0x80 + 1, 0x60); /* next */
4697 /* Device flags */
4698 PDMPciDevSetWord( pPciDev, 0x80 + 2,
4699 1 /* version */
4700 | (VBOX_PCI_EXP_TYPE_ROOT_INT_EP << 4) /* Root Complex Integrated Endpoint */
4701 | (100 << 9) /* MSI */ );
4702 /* Device capabilities */
4703 PDMPciDevSetDWord( pPciDev, 0x80 + 4, VBOX_PCI_EXP_DEVCAP_FLRESET);
4704 /* Device control */
4705 PDMPciDevSetWord( pPciDev, 0x80 + 8, 0);
4706 /* Device status */
4707 PDMPciDevSetWord( pPciDev, 0x80 + 10, 0);
4708 /* Link caps */
4709 PDMPciDevSetDWord( pPciDev, 0x80 + 12, 0);
4710 /* Link control */
4711 PDMPciDevSetWord( pPciDev, 0x80 + 16, 0);
4712 /* Link status */
4713 PDMPciDevSetWord( pPciDev, 0x80 + 18, 0);
4714 /* Slot capabilities */
4715 PDMPciDevSetDWord( pPciDev, 0x80 + 20, 0);
4716 /* Slot control */
4717 PDMPciDevSetWord( pPciDev, 0x80 + 24, 0);
4718 /* Slot status */
4719 PDMPciDevSetWord( pPciDev, 0x80 + 26, 0);
4720 /* Root control */
4721 PDMPciDevSetWord( pPciDev, 0x80 + 28, 0);
4722 /* Root capabilities */
4723 PDMPciDevSetWord( pPciDev, 0x80 + 30, 0);
4724 /* Root status */
4725 PDMPciDevSetDWord( pPciDev, 0x80 + 32, 0);
4726 /* Device capabilities 2 */
4727 PDMPciDevSetDWord( pPciDev, 0x80 + 36, 0);
4728 /* Device control 2 */
4729 PDMPciDevSetQWord( pPciDev, 0x80 + 40, 0);
4730 /* Link control 2 */
4731 PDMPciDevSetQWord( pPciDev, 0x80 + 48, 0);
4732 /* Slot control 2 */
4733 PDMPciDevSetWord( pPciDev, 0x80 + 56, 0);
4734# endif /* HDA_AS_PCI_EXPRESS */
4735
4736 /*
4737 * Register the PCI device.
4738 */
4739 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
4740 AssertRCReturn(rc, rc);
4741
4742 /** @todo r=bird: The IOMMMIO_FLAGS_READ_DWORD flag isn't entirely optimal,
4743 * as several frequently used registers aren't dword sized. 6.0 and earlier
4744 * will go to ring-3 to handle accesses to any such register, where-as 6.1 and
4745 * later will do trivial register reads in ring-0. Real optimal code would use
4746 * IOMMMIO_FLAGS_READ_PASSTHRU and do the necessary extra work to deal with
4747 * anything the guest may throw at us. */
4748 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, 0, 0x4000, PCI_ADDRESS_SPACE_MEM, hdaMmioWrite, hdaMmioRead, NULL /*pvUser*/,
4749 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU, "HDA", &pThis->hMmio);
4750 AssertRCReturn(rc, rc);
4751
4752# ifdef VBOX_WITH_MSI_DEVICES
4753 PDMMSIREG MsiReg;
4754 RT_ZERO(MsiReg);
4755 MsiReg.cMsiVectors = 1;
4756 MsiReg.iMsiCapOffset = 0x60;
4757 MsiReg.iMsiNextOffset = 0x50;
4758 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
4759 if (RT_FAILURE(rc))
4760 {
4761 /* That's OK, we can work without MSI */
4762 PDMPciDevSetCapabilityList(pPciDev, 0x50);
4763 }
4764# endif
4765
4766 rc = PDMDevHlpSSMRegister(pDevIns, HDA_SAVED_STATE_VERSION, sizeof(*pThis), hdaR3SaveExec, hdaR3LoadExec);
4767 AssertRCReturn(rc, rc);
4768
4769# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
4770 LogRel(("HDA: Asynchronous I/O enabled\n"));
4771# endif
4772
4773 /*
4774 * Attach drivers. We ASSUME they are configured consecutively without any
4775 * gaps, so we stop when we hit the first LUN w/o a driver configured.
4776 */
4777 for (unsigned iLun = 0; ; iLun++)
4778 {
4779 AssertBreak(iLun < UINT8_MAX);
4780 LogFunc(("Trying to attach driver for LUN#%u ...\n", iLun));
4781 rc = hdaR3AttachInternal(pDevIns, pThis, pThisCC, iLun, 0 /* fFlags */, NULL /* ppDrv */);
4782 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4783 {
4784 LogFunc(("cLUNs=%u\n", iLun));
4785 break;
4786 }
4787 if (rc == VERR_AUDIO_BACKEND_INIT_FAILED)
4788 {
4789 hdaR3ReconfigLunWithNullAudio(pDevIns, pThis, pThisCC, iLun); /* Pretend attaching to the NULL audio backend will never fail. */
4790 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
4791 N_("Host audio backend initialization has failed. Selecting the NULL audio backend with the consequence that no sound is audible"));
4792 }
4793 else
4794 AssertLogRelMsgReturn(RT_SUCCESS(rc), ("LUN#%u: rc=%Rrc\n", iLun, rc), rc);
4795 }
4796
4797 /*
4798 * Create the mixer.
4799 */
4800 uint32_t fMixer = AUDMIXER_FLAGS_NONE;
4801 if (pThisCC->Dbg.fEnabled)
4802 fMixer |= AUDMIXER_FLAGS_DEBUG;
4803 rc = AudioMixerCreate("HDA Mixer", fMixer, &pThisCC->pMixer);
4804 AssertRCReturn(rc, rc);
4805
4806 /*
4807 * Add mixer output sinks.
4808 */
4809# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
4810 rc = AudioMixerCreateSink(pThisCC->pMixer, "[Playback] Front", AUDMIXSINKDIR_OUTPUT, &pThisCC->SinkFront.pMixSink);
4811 AssertRCReturn(rc, rc);
4812 rc = AudioMixerCreateSink(pThisCC->pMixer, "[Playback] Center / Subwoofer", AUDMIXSINKDIR_OUTPUT, &pThisCC->SinkCenterLFE.pMixSink);
4813 AssertRCReturn(rc, rc);
4814 rc = AudioMixerCreateSink(pThisCC->pMixer, "[Playback] Rear", AUDMIXSINKDIR_OUTPUT, &pThisCC->SinkRear.pMixSink);
4815 AssertRCReturn(rc, rc);
4816# else
4817 rc = AudioMixerCreateSink(pThisCC->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThisCC->SinkFront.pMixSink);
4818 AssertRCReturn(rc, rc);
4819# endif /* VBOX_WITH_AUDIO_HDA_51_SURROUND */
4820
4821 /*
4822 * Add mixer input sinks.
4823 */
4824 rc = AudioMixerCreateSink(pThisCC->pMixer, "[Recording] Line In", AUDMIXSINKDIR_INPUT, &pThisCC->SinkLineIn.pMixSink);
4825 AssertRCReturn(rc, rc);
4826# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
4827 rc = AudioMixerCreateSink(pThisCC->pMixer, "[Recording] Microphone In", AUDMIXSINKDIR_INPUT, &pThisCC->SinkMicIn.pMixSink);
4828 AssertRCReturn(rc, rc);
4829# endif
4830
4831 /* There is no master volume control. Set the master to max. */
4832 PDMAUDIOVOLUME vol = { false, 255, 255 };
4833 rc = AudioMixerSetMasterVolume(pThisCC->pMixer, &vol);
4834 AssertRCReturn(rc, rc);
4835
4836 /* Allocate codec. */
4837 PHDACODECR3 pCodecR3 = (PHDACODECR3)RTMemAllocZ(sizeof(HDACODECR3));
4838 AssertPtrReturn(pCodecR3, VERR_NO_MEMORY);
4839
4840 /* Set codec callbacks to this controller. */
4841 pCodecR3->pDevIns = pDevIns;
4842 pCodecR3->pfnCbMixerAddStream = hdaR3MixerAddStream;
4843 pCodecR3->pfnCbMixerRemoveStream = hdaR3MixerRemoveStream;
4844 pCodecR3->pfnCbMixerControl = hdaR3MixerControl;
4845 pCodecR3->pfnCbMixerSetVolume = hdaR3MixerSetVolume;
4846
4847 /* Construct the common + R3 codec part. */
4848 rc = hdaR3CodecConstruct(pDevIns, &pThis->Codec, pCodecR3, 0 /* Codec index */, pCfg);
4849 AssertRCReturn(rc, rc);
4850
4851 pThisCC->pCodec = pCodecR3;
4852
4853 /* ICH6 datasheet defines 0 values for SVID and SID (18.1.14-15), which together with values returned for
4854 verb F20 should provide device/codec recognition. */
4855 Assert(pThis->Codec.u16VendorId);
4856 Assert(pThis->Codec.u16DeviceId);
4857 PDMPciDevSetSubSystemVendorId(pPciDev, pThis->Codec.u16VendorId); /* 2c ro - intel.) */
4858 PDMPciDevSetSubSystemId( pPciDev, pThis->Codec.u16DeviceId); /* 2e ro. */
4859
4860 /*
4861 * Create the per stream timers and the asso.
4862 *
4863 * We must the critical section for the timers as the device has a
4864 * noop section associated with it.
4865 *
4866 * Note: Use TMCLOCK_VIRTUAL_SYNC here, as the guest's HDA driver relies
4867 * on exact (virtual) DMA timing and uses DMA Position Buffers
4868 * instead of the LPIB registers.
4869 */
4870 /** @todo r=bird: The need to use virtual sync is perhaps because TM
4871 * doesn't schedule regular TMCLOCK_VIRTUAL timers as accurately as it
4872 * should (VT-x preemption timer, etc). Hope to address that before
4873 * long. @bugref{9943}. */
4874 static const char * const s_apszNames[] =
4875 { "HDA SD0", "HDA SD1", "HDA SD2", "HDA SD3", "HDA SD4", "HDA SD5", "HDA SD6", "HDA SD7", };
4876 AssertCompile(RT_ELEMENTS(s_apszNames) == HDA_MAX_STREAMS);
4877 for (size_t i = 0; i < HDA_MAX_STREAMS; i++)
4878 {
4879 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hdaR3Timer, (void *)(uintptr_t)i,
4880 TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_NO_RING0,
4881 s_apszNames[i], &pThis->aStreams[i].hTimer);
4882 AssertRCReturn(rc, rc);
4883
4884 rc = PDMDevHlpTimerSetCritSect(pDevIns, pThis->aStreams[i].hTimer, &pThis->CritSect);
4885 AssertRCReturn(rc, rc);
4886 }
4887
4888 /*
4889 * Create all hardware streams.
4890 */
4891 for (uint8_t i = 0; i < HDA_MAX_STREAMS; ++i)
4892 {
4893 rc = hdaR3StreamConstruct(&pThis->aStreams[i], &pThisCC->aStreams[i], pThis, pThisCC, i /* u8SD */);
4894 AssertRCReturn(rc, rc);
4895 }
4896
4897# ifdef VBOX_WITH_AUDIO_HDA_ONETIME_INIT
4898 /*
4899 * Initialize the driver chain.
4900 */
4901 PHDADRIVER pDrv;
4902 RTListForEach(&pThisCC->lstDrv, pDrv, HDADRIVER, Node)
4903 {
4904 /*
4905 * Only primary drivers are critical for the VM to run. Everything else
4906 * might not worth showing an own error message box in the GUI.
4907 */
4908 if (!(pDrv->fFlags & PDMAUDIODRVFLAGS_PRIMARY))
4909 continue;
4910
4911 PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
4912 AssertPtr(pCon);
4913
4914 bool fValidLineIn = AudioMixerStreamIsValid(pDrv->LineIn.pMixStrm);
4915# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
4916 bool fValidMicIn = AudioMixerStreamIsValid(pDrv->MicIn.pMixStrm);
4917# endif
4918 bool fValidOut = AudioMixerStreamIsValid(pDrv->Front.pMixStrm);
4919# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
4920 /** @todo Anything to do here? */
4921# endif
4922
4923 if ( !fValidLineIn
4924# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
4925 && !fValidMicIn
4926# endif
4927 && !fValidOut)
4928 {
4929 LogRel(("HDA: Falling back to NULL backend (no sound audible)\n"));
4930 hdaR3Reset(pDevIns);
4931 hdaR3ReconfigLunWithNullAudio(pThis, pDrv->uLUN);
4932 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
4933 N_("No audio devices could be opened. "
4934 "Selecting the NULL audio backend with the consequence that no sound is audible"));
4935 }
4936 else
4937 {
4938 bool fWarn = false;
4939
4940 PDMAUDIOBACKENDCFG BackendCfg;
4941 int rc2 = pCon->pfnGetConfig(pCon, &BackendCfg);
4942 if (RT_SUCCESS(rc2))
4943 {
4944 if (BackendCfg.cMaxStreamsIn)
4945 {
4946# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
4947 /* If the audio backend supports two or more input streams at once,
4948 * warn if one of our two inputs (microphone-in and line-in) failed to initialize. */
4949 if (BackendCfg.cMaxStreamsIn >= 2)
4950 fWarn = !fValidLineIn || !fValidMicIn;
4951 /* If the audio backend only supports one input stream at once (e.g. pure ALSA, and
4952 * *not* ALSA via PulseAudio plugin!), only warn if both of our inputs failed to initialize.
4953 * One of the two simply is not in use then. */
4954 else if (BackendCfg.cMaxStreamsIn == 1)
4955 fWarn = !fValidLineIn && !fValidMicIn;
4956 /* Don't warn if our backend is not able of supporting any input streams at all. */
4957# else /* !VBOX_WITH_AUDIO_HDA_MIC_IN */
4958 /* We only have line-in as input source. */
4959 fWarn = !fValidLineIn;
4960# endif /* !VBOX_WITH_AUDIO_HDA_MIC_IN */
4961 }
4962
4963 if ( !fWarn
4964 && BackendCfg.cMaxStreamsOut)
4965 fWarn = !fValidOut;
4966 }
4967 else
4968 {
4969 LogRel(("HDA: Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n", pDrv->uLUN, rc2));
4970 fWarn = true;
4971 }
4972
4973 if (fWarn)
4974 {
4975 char szMissingStreams[255];
4976 size_t len = 0;
4977 if (!fValidLineIn)
4978 {
4979 LogRel(("HDA: WARNING: Unable to open PCM line input for LUN #%RU8!\n", pDrv->uLUN));
4980 len = RTStrPrintf(szMissingStreams, sizeof(szMissingStreams), "PCM Input");
4981 }
4982# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
4983 if (!fValidMicIn)
4984 {
4985 LogRel(("HDA: WARNING: Unable to open PCM microphone input for LUN #%RU8!\n", pDrv->uLUN));
4986 len += RTStrPrintf(szMissingStreams + len,
4987 sizeof(szMissingStreams) - len, len ? ", PCM Microphone" : "PCM Microphone");
4988 }
4989# endif /* VBOX_WITH_AUDIO_HDA_MIC_IN */
4990 if (!fValidOut)
4991 {
4992 LogRel(("HDA: WARNING: Unable to open PCM output for LUN #%RU8!\n", pDrv->uLUN));
4993 len += RTStrPrintf(szMissingStreams + len,
4994 sizeof(szMissingStreams) - len, len ? ", PCM Output" : "PCM Output");
4995 }
4996
4997 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
4998 N_("Some HDA audio streams (%s) could not be opened. "
4999 "Guest applications generating audio output or depending on audio input may hang. "
5000 "Make sure your host audio device is working properly. "
5001 "Check the logfile for error messages of the audio subsystem"), szMissingStreams);
5002 }
5003 }
5004 }
5005# endif /* VBOX_WITH_AUDIO_HDA_ONETIME_INIT */
5006
5007 hdaR3Reset(pDevIns);
5008
5009 /*
5010 * Info items and string formatter types. The latter is non-optional as
5011 * the info handles use (at least some of) the custom types and we cannot
5012 * accept screwing formatting.
5013 */
5014 PDMDevHlpDBGFInfoRegister(pDevIns, "hda", "HDA info. (hda [register case-insensitive])", hdaR3DbgInfo);
5015 PDMDevHlpDBGFInfoRegister(pDevIns, "hdabdle", "HDA stream BDLE info. (hdabdle [stream number])", hdaR3DbgInfoBDLE);
5016 PDMDevHlpDBGFInfoRegister(pDevIns, "hdastream", "HDA stream info. (hdastream [stream number])", hdaR3DbgInfoStream);
5017 PDMDevHlpDBGFInfoRegister(pDevIns, "hdcnodes", "HDA codec nodes.", hdaR3DbgInfoCodecNodes);
5018 PDMDevHlpDBGFInfoRegister(pDevIns, "hdcselector", "HDA codec's selector states [node number].", hdaR3DbgInfoCodecSelector);
5019 PDMDevHlpDBGFInfoRegister(pDevIns, "hdamixer", "HDA mixer state.", hdaR3DbgInfoMixer);
5020
5021 rc = RTStrFormatTypeRegister("bdle", hdaR3StrFmtBDLE, NULL);
5022 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5023 rc = RTStrFormatTypeRegister("sdctl", hdaR3StrFmtSDCTL, NULL);
5024 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5025 rc = RTStrFormatTypeRegister("sdsts", hdaR3StrFmtSDSTS, NULL);
5026 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5027 rc = RTStrFormatTypeRegister("sdfifos", hdaR3StrFmtSDFIFOS, NULL);
5028 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5029 rc = RTStrFormatTypeRegister("sdfifow", hdaR3StrFmtSDFIFOW, NULL);
5030 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS, ("%Rrc\n", rc), rc);
5031
5032 /*
5033 * Asserting sanity.
5034 */
5035 for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
5036 {
5037 struct HDAREGDESC const *pReg = &g_aHdaRegMap[i];
5038 struct HDAREGDESC const *pNextReg = i + 1 < RT_ELEMENTS(g_aHdaRegMap) ? &g_aHdaRegMap[i + 1] : NULL;
5039
5040 /* binary search order. */
5041 AssertReleaseMsg(!pNextReg || pReg->offset + pReg->size <= pNextReg->offset,
5042 ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
5043 i, pReg->offset, pReg->size, i + 1, pNextReg->offset, pNextReg->size));
5044
5045 /* alignment. */
5046 AssertReleaseMsg( pReg->size == 1
5047 || (pReg->size == 2 && (pReg->offset & 1) == 0)
5048 || (pReg->size == 3 && (pReg->offset & 3) == 0)
5049 || (pReg->size == 4 && (pReg->offset & 3) == 0),
5050 ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
5051
5052 /* registers are packed into dwords - with 3 exceptions with gaps at the end of the dword. */
5053 AssertRelease(((pReg->offset + pReg->size) & 3) == 0 || pNextReg);
5054 if (pReg->offset & 3)
5055 {
5056 struct HDAREGDESC const *pPrevReg = i > 0 ? &g_aHdaRegMap[i - 1] : NULL;
5057 AssertReleaseMsg(pPrevReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
5058 if (pPrevReg)
5059 AssertReleaseMsg(pPrevReg->offset + pPrevReg->size == pReg->offset,
5060 ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
5061 i - 1, pPrevReg->offset, pPrevReg->size, i + 1, pReg->offset, pReg->size));
5062 }
5063#if 0
5064 if ((pReg->offset + pReg->size) & 3)
5065 {
5066 AssertReleaseMsg(pNextReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
5067 if (pNextReg)
5068 AssertReleaseMsg(pReg->offset + pReg->size == pNextReg->offset,
5069 ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
5070 i, pReg->offset, pReg->size, i + 1, pNextReg->offset, pNextReg->size));
5071 }
5072#endif
5073 /* The final entry is a full DWORD, no gaps! Allows shortcuts. */
5074 AssertReleaseMsg(pNextReg || ((pReg->offset + pReg->size) & 3) == 0,
5075 ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
5076 }
5077
5078# ifdef VBOX_WITH_STATISTICS
5079 /*
5080 * Register statistics.
5081 */
5082 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn, STAMTYPE_PROFILE, "Input", STAMUNIT_TICKS_PER_CALL, "Profiling input.");
5083 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatOut, STAMTYPE_PROFILE, "Output", STAMUNIT_TICKS_PER_CALL, "Profiling output.");
5084 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, "BytesRead" , STAMUNIT_BYTES, "Bytes read from HDA emulation.");
5085 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "BytesWritten", STAMUNIT_BYTES, "Bytes written to HDA emulation.");
5086
5087 AssertCompile(RT_ELEMENTS(g_aHdaRegMap) == HDA_NUM_REGS);
5088 AssertCompile(RT_ELEMENTS(pThis->aStatRegReads) == HDA_NUM_REGS);
5089 AssertCompile(RT_ELEMENTS(pThis->aStatRegReadsToR3) == HDA_NUM_REGS);
5090 AssertCompile(RT_ELEMENTS(pThis->aStatRegWrites) == HDA_NUM_REGS);
5091 AssertCompile(RT_ELEMENTS(pThis->aStatRegWritesToR3) == HDA_NUM_REGS);
5092 for (size_t i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
5093 {
5094 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegReads[i], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
5095 g_aHdaRegMap[i].desc, "Regs/%03x-%s-Reads", g_aHdaRegMap[i].offset, g_aHdaRegMap[i].abbrev);
5096 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegReadsToR3[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5097 g_aHdaRegMap[i].desc, "Regs/%03x-%s-Reads-ToR3", g_aHdaRegMap[i].offset, g_aHdaRegMap[i].abbrev);
5098 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegWrites[i], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
5099 g_aHdaRegMap[i].desc, "Regs/%03x-%s-Writes", g_aHdaRegMap[i].offset, g_aHdaRegMap[i].abbrev);
5100 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatRegWritesToR3[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
5101 g_aHdaRegMap[i].desc, "Regs/%03x-%s-Writes-ToR3", g_aHdaRegMap[i].offset, g_aHdaRegMap[i].abbrev);
5102 }
5103 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiReadsR3, STAMTYPE_COUNTER, "RegMultiReadsR3", STAMUNIT_OCCURENCES, "Register read not targeting just one register, handled in ring-3");
5104 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiReadsRZ, STAMTYPE_COUNTER, "RegMultiReadsRZ", STAMUNIT_OCCURENCES, "Register read not targeting just one register, handled in ring-0");
5105 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiWritesR3, STAMTYPE_COUNTER, "RegMultiWritesR3", STAMUNIT_OCCURENCES, "Register writes not targeting just one register, handled in ring-3");
5106 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegMultiWritesRZ, STAMTYPE_COUNTER, "RegMultiWritesRZ", STAMUNIT_OCCURENCES, "Register writes not targeting just one register, handled in ring-0");
5107 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegSubWriteR3, STAMTYPE_COUNTER, "RegSubWritesR3", STAMUNIT_OCCURENCES, "Trucated register writes, handled in ring-3");
5108 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegSubWriteRZ, STAMTYPE_COUNTER, "RegSubWritesRZ", STAMUNIT_OCCURENCES, "Trucated register writes, handled in ring-0");
5109 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegUnknownReads, STAMTYPE_COUNTER, "RegUnknownReads", STAMUNIT_OCCURENCES, "Reads of unknown registers.");
5110 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegUnknownWrites, STAMTYPE_COUNTER, "RegUnknownWrites", STAMUNIT_OCCURENCES, "Writes to unknown registers.");
5111 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegWritesBlockedByReset, STAMTYPE_COUNTER, "RegWritesBlockedByReset", STAMUNIT_OCCURENCES, "Writes blocked by pending reset (GCTL/CRST)");
5112 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatRegWritesBlockedByRun, STAMTYPE_COUNTER, "RegWritesBlockedByRun", STAMUNIT_OCCURENCES, "Writes blocked by byte RUN bit.");
5113# endif
5114
5115 return VINF_SUCCESS;
5116}
5117
5118#else /* !IN_RING3 */
5119
5120/**
5121 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
5122 */
5123static DECLCALLBACK(int) hdaRZConstruct(PPDMDEVINS pDevIns)
5124{
5125 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* this shall come first */
5126 PHDASTATE pThis = PDMDEVINS_2_DATA(pDevIns, PHDASTATE);
5127 PHDASTATER0 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PHDASTATER0);
5128
5129 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
5130 AssertRCReturn(rc, rc);
5131
5132 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, hdaMmioWrite, hdaMmioRead, NULL /*pvUser*/);
5133 AssertRCReturn(rc, rc);
5134
5135 /* Construct the R0 codec part. */
5136 rc = hdaR0CodecConstruct(pDevIns, &pThis->Codec, &pThisCC->Codec);
5137 AssertRCReturn(rc, rc);
5138
5139 return VINF_SUCCESS;
5140}
5141
5142#endif /* !IN_RING3 */
5143
5144/**
5145 * The device registration structure.
5146 */
5147const PDMDEVREG g_DeviceHDA =
5148{
5149 /* .u32Version = */ PDM_DEVREG_VERSION,
5150 /* .uReserved0 = */ 0,
5151 /* .szName = */ "hda",
5152 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
5153 /* .fClass = */ PDM_DEVREG_CLASS_AUDIO,
5154 /* .cMaxInstances = */ 1,
5155 /* .uSharedVersion = */ 42,
5156 /* .cbInstanceShared = */ sizeof(HDASTATE),
5157 /* .cbInstanceCC = */ CTX_EXPR(sizeof(HDASTATER3), sizeof(HDASTATER0), 0),
5158 /* .cbInstanceRC = */ 0,
5159 /* .cMaxPciDevices = */ 1,
5160 /* .cMaxMsixVectors = */ 0,
5161 /* .pszDescription = */ "Intel HD Audio Controller",
5162#if defined(IN_RING3)
5163 /* .pszRCMod = */ "VBoxDDRC.rc",
5164 /* .pszR0Mod = */ "VBoxDDR0.r0",
5165 /* .pfnConstruct = */ hdaR3Construct,
5166 /* .pfnDestruct = */ hdaR3Destruct,
5167 /* .pfnRelocate = */ NULL,
5168 /* .pfnMemSetup = */ NULL,
5169 /* .pfnPowerOn = */ NULL,
5170 /* .pfnReset = */ hdaR3Reset,
5171 /* .pfnSuspend = */ NULL,
5172 /* .pfnResume = */ NULL,
5173 /* .pfnAttach = */ hdaR3Attach,
5174 /* .pfnDetach = */ hdaR3Detach,
5175 /* .pfnQueryInterface = */ NULL,
5176 /* .pfnInitComplete = */ NULL,
5177 /* .pfnPowerOff = */ hdaR3PowerOff,
5178 /* .pfnSoftReset = */ NULL,
5179 /* .pfnReserved0 = */ NULL,
5180 /* .pfnReserved1 = */ NULL,
5181 /* .pfnReserved2 = */ NULL,
5182 /* .pfnReserved3 = */ NULL,
5183 /* .pfnReserved4 = */ NULL,
5184 /* .pfnReserved5 = */ NULL,
5185 /* .pfnReserved6 = */ NULL,
5186 /* .pfnReserved7 = */ NULL,
5187#elif defined(IN_RING0)
5188 /* .pfnEarlyConstruct = */ NULL,
5189 /* .pfnConstruct = */ hdaRZConstruct,
5190 /* .pfnDestruct = */ NULL,
5191 /* .pfnFinalDestruct = */ NULL,
5192 /* .pfnRequest = */ NULL,
5193 /* .pfnReserved0 = */ NULL,
5194 /* .pfnReserved1 = */ NULL,
5195 /* .pfnReserved2 = */ NULL,
5196 /* .pfnReserved3 = */ NULL,
5197 /* .pfnReserved4 = */ NULL,
5198 /* .pfnReserved5 = */ NULL,
5199 /* .pfnReserved6 = */ NULL,
5200 /* .pfnReserved7 = */ NULL,
5201#elif defined(IN_RC)
5202 /* .pfnConstruct = */ hdaRZConstruct,
5203 /* .pfnReserved0 = */ NULL,
5204 /* .pfnReserved1 = */ NULL,
5205 /* .pfnReserved2 = */ NULL,
5206 /* .pfnReserved3 = */ NULL,
5207 /* .pfnReserved4 = */ NULL,
5208 /* .pfnReserved5 = */ NULL,
5209 /* .pfnReserved6 = */ NULL,
5210 /* .pfnReserved7 = */ NULL,
5211#else
5212# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5213#endif
5214 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
5215};
5216
5217#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
5218
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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