VirtualBox

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

Last change on this file since 101539 was 99310, checked in by vboxsync, 21 months ago

Audio/HDA: Additional checks for register aliasing. bugref:10349

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