VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevHDA.cpp@ 88112

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

Audio,DevHDA: Made PDMAUDIOPCMPROPS_F2B and PDMAUDIOPCMPROPS_B2F work for 5.1 and other frame sizes that aren't a power of two. Rewrote hdaR3StreamDoDmaOutput. Mapping is now done using converter functions rather than the complexity in hdaR3StreamTransfer. Probably fixes some recent goofs in the DMA period heuristics for non-stereo guest streams, I've renamed the members to make it clear what's what. bugref:9890

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