VirtualBox

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

Last change on this file since 98169 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

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