VirtualBox

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

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

DevHDA: Fix incorrect version check in hdaR3LoadExec causing it to attempt skip an non-existing HDASTREAMPERIOD structure. Must take the AIO lock when saving the internal DMA buffer or we risk racing the AIO thread and get a messed up result. Must run the hdaR3LoadExecTail in a load-done callback after the entire VM state has been loaded, or we'll end up asserting when we try to raise interrupts too early. That code must also do some extra locking to avoid assertions in TM. bugref:9890

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