VirtualBox

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

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

Audio/Dev*: Overhauled the attach/detach code a little, making attach fail if the configured driver doesn't have a PDMIADUIOCONNECTOR interface among other things. bugref:9890

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