VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevHda.cpp@ 89878

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

DevHda: The compile time feature enable/disable defines must live in DevHda.h. bugref:9890

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

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