VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevIchAc97.cpp@ 89747

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

DevIchAc97: Addressed todo in ichac97R3StreamSetUp regarding zero rate, making it return VERR_OUT_OF_RANGE rather than VINF_SUCCESS and check for any unsupported uHz values. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 183.4 KB
Line 
1/* $Id: DevIchAc97.cpp 89743 2021-06-16 13:49:46Z vboxsync $ */
2/** @file
3 * DevIchAc97 - VBox ICH AC97 Audio Controller.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_AC97
23#include <VBox/log.h>
24#include <VBox/vmm/pdmdev.h>
25#include <VBox/vmm/pdmaudioifs.h>
26#include <VBox/vmm/pdmaudioinline.h>
27#include <VBox/AssertGuest.h>
28
29#include <iprt/assert.h>
30#ifdef IN_RING3
31# ifdef DEBUG
32# include <iprt/file.h>
33# endif
34# include <iprt/mem.h>
35# include <iprt/semaphore.h>
36# include <iprt/string.h>
37# include <iprt/uuid.h>
38# include <iprt/zero.h>
39#endif
40
41#include "VBoxDD.h"
42
43#include "AudioMixBuffer.h"
44#include "AudioMixer.h"
45#include "AudioHlp.h"
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51/** Current saved state version. */
52#define AC97_SAVED_STATE_VERSION 1
53
54/** Default timer frequency (in Hz). */
55#define AC97_TIMER_HZ_DEFAULT 100
56
57/** Maximum number of streams we support. */
58#define AC97_MAX_STREAMS 3
59
60/** Maximum FIFO size (in bytes) - unused. */
61#define AC97_FIFO_MAX 256
62
63/** @name AC97_SR_XXX - Status Register Bits (AC97_NABM_OFF_SR, PI_SR, PO_SR, MC_SR).
64 * @{ */
65#define AC97_SR_FIFOE RT_BIT(4) /**< rwc, FIFO error. */
66#define AC97_SR_BCIS RT_BIT(3) /**< rwc, Buffer completion interrupt status. */
67#define AC97_SR_LVBCI RT_BIT(2) /**< rwc, Last valid buffer completion interrupt. */
68#define AC97_SR_CELV RT_BIT(1) /**< ro, Current equals last valid. */
69#define AC97_SR_DCH RT_BIT(0) /**< ro, Controller halted. */
70#define AC97_SR_VALID_MASK (RT_BIT(5) - 1)
71#define AC97_SR_WCLEAR_MASK (AC97_SR_FIFOE | AC97_SR_BCIS | AC97_SR_LVBCI)
72#define AC97_SR_RO_MASK (AC97_SR_DCH | AC97_SR_CELV)
73#define AC97_SR_INT_MASK (AC97_SR_FIFOE | AC97_SR_BCIS | AC97_SR_LVBCI)
74/** @} */
75
76/** @name AC97_CR_XXX - Control Register Bits (AC97_NABM_OFF_CR, PI_CR, PO_CR, MC_CR).
77 * @{ */
78#define AC97_CR_IOCE RT_BIT(4) /**< rw, Interrupt On Completion Enable. */
79#define AC97_CR_FEIE RT_BIT(3) /**< rw FIFO Error Interrupt Enable. */
80#define AC97_CR_LVBIE RT_BIT(2) /**< rw Last Valid Buffer Interrupt Enable. */
81#define AC97_CR_RR RT_BIT(1) /**< rw Reset Registers. */
82#define AC97_CR_RPBM RT_BIT(0) /**< rw Run/Pause Bus Master. */
83#define AC97_CR_VALID_MASK (RT_BIT(5) - 1)
84#define AC97_CR_DONT_CLEAR_MASK (AC97_CR_IOCE | AC97_CR_FEIE | AC97_CR_LVBIE)
85/** @} */
86
87/** @name AC97_GC_XXX - Global Control Bits (see AC97_GLOB_CNT). */
88#define AC97_GC_WR 4 /**< rw Warm reset. */
89#define AC97_GC_CR 2 /**< rw Cold reset. */
90#define AC97_GC_VALID_MASK (RT_BIT(6) - 1)
91/** @} */
92
93/** @name AC97_GS_XXX - Global Status Bits (AC97_GLOB_STA).
94 * @{ */
95#define AC97_GS_MD3 RT_BIT(17) /**< rw */
96#define AC97_GS_AD3 RT_BIT(16) /**< rw */
97#define AC97_GS_RCS RT_BIT(15) /**< rwc */
98#define AC97_GS_B3S12 RT_BIT(14) /**< ro */
99#define AC97_GS_B2S12 RT_BIT(13) /**< ro */
100#define AC97_GS_B1S12 RT_BIT(12) /**< ro */
101#define AC97_GS_S1R1 RT_BIT(11) /**< rwc */
102#define AC97_GS_S0R1 RT_BIT(10) /**< rwc */
103#define AC97_GS_S1CR RT_BIT(9) /**< ro */
104#define AC97_GS_S0CR RT_BIT(8) /**< ro */
105#define AC97_GS_MINT RT_BIT(7) /**< ro */
106#define AC97_GS_POINT RT_BIT(6) /**< ro */
107#define AC97_GS_PIINT RT_BIT(5) /**< ro */
108#define AC97_GS_RSRVD (RT_BIT(4) | RT_BIT(3))
109#define AC97_GS_MOINT RT_BIT(2) /**< ro */
110#define AC97_GS_MIINT RT_BIT(1) /**< ro */
111#define AC97_GS_GSCI RT_BIT(0) /**< rwc */
112#define AC97_GS_RO_MASK ( AC97_GS_B3S12 \
113 | AC97_GS_B2S12 \
114 | AC97_GS_B1S12 \
115 | AC97_GS_S1CR \
116 | AC97_GS_S0CR \
117 | AC97_GS_MINT \
118 | AC97_GS_POINT \
119 | AC97_GS_PIINT \
120 | AC97_GS_RSRVD \
121 | AC97_GS_MOINT \
122 | AC97_GS_MIINT)
123#define AC97_GS_VALID_MASK (RT_BIT(18) - 1)
124#define AC97_GS_WCLEAR_MASK (AC97_GS_RCS | AC97_GS_S1R1 | AC97_GS_S0R1 | AC97_GS_GSCI)
125/** @} */
126
127/** @name Buffer Descriptor (BDLE, BDL).
128 * @{ */
129#define AC97_BD_IOC RT_BIT(31) /**< Interrupt on Completion. */
130#define AC97_BD_BUP RT_BIT(30) /**< Buffer Underrun Policy. */
131
132#define AC97_BD_LEN_MASK 0xFFFF /**< Mask for the BDL buffer length. */
133
134#define AC97_BD_LEN_CTL_MBZ UINT32_C(0x3fff0000) /**< Must-be-zero mask for AC97BDLE.ctl_len. */
135
136#define AC97_MAX_BDLE 32 /**< Maximum number of BDLEs. */
137/** @} */
138
139/** @name Extended Audio ID Register (EAID).
140 * @{ */
141#define AC97_EAID_VRA RT_BIT(0) /**< Variable Rate Audio. */
142#define AC97_EAID_VRM RT_BIT(3) /**< Variable Rate Mic Audio. */
143#define AC97_EAID_REV0 RT_BIT(10) /**< AC'97 revision compliance. */
144#define AC97_EAID_REV1 RT_BIT(11) /**< AC'97 revision compliance. */
145/** @} */
146
147/** @name Extended Audio Control and Status Register (EACS).
148 * @{ */
149#define AC97_EACS_VRA RT_BIT(0) /**< Variable Rate Audio (4.2.1.1). */
150#define AC97_EACS_VRM RT_BIT(3) /**< Variable Rate Mic Audio (4.2.1.1). */
151/** @} */
152
153/** @name Baseline Audio Register Set (BARS).
154 * @{ */
155#define AC97_BARS_VOL_MASK 0x1f /**< Volume mask for the Baseline Audio Register Set (5.7.2). */
156#define AC97_BARS_GAIN_MASK 0x0f /**< Gain mask for the Baseline Audio Register Set. */
157#define AC97_BARS_VOL_MUTE_SHIFT 15 /**< Mute bit shift for the Baseline Audio Register Set (5.7.2). */
158/** @} */
159
160/** AC'97 uses 1.5dB steps, we use 0.375dB steps: 1 AC'97 step equals 4 PDM steps. */
161#define AC97_DB_FACTOR 4
162
163/** @name Recording inputs?
164 * @{ */
165#define AC97_REC_MIC UINT8_C(0)
166#define AC97_REC_CD UINT8_C(1)
167#define AC97_REC_VIDEO UINT8_C(2)
168#define AC97_REC_AUX UINT8_C(3)
169#define AC97_REC_LINE_IN UINT8_C(4)
170#define AC97_REC_STEREO_MIX UINT8_C(5)
171#define AC97_REC_MONO_MIX UINT8_C(6)
172#define AC97_REC_PHONE UINT8_C(7)
173#define AC97_REC_MASK UINT8_C(7)
174/** @} */
175
176/** @name Mixer registers / NAM BAR registers?
177 * @{ */
178#define AC97_Reset 0x00
179#define AC97_Master_Volume_Mute 0x02
180#define AC97_Headphone_Volume_Mute 0x04 /**< Also known as AUX, see table 16, section 5.7. */
181#define AC97_Master_Volume_Mono_Mute 0x06
182#define AC97_Master_Tone_RL 0x08
183#define AC97_PC_BEEP_Volume_Mute 0x0a
184#define AC97_Phone_Volume_Mute 0x0c
185#define AC97_Mic_Volume_Mute 0x0e
186#define AC97_Line_In_Volume_Mute 0x10
187#define AC97_CD_Volume_Mute 0x12
188#define AC97_Video_Volume_Mute 0x14
189#define AC97_Aux_Volume_Mute 0x16
190#define AC97_PCM_Out_Volume_Mute 0x18
191#define AC97_Record_Select 0x1a
192#define AC97_Record_Gain_Mute 0x1c
193#define AC97_Record_Gain_Mic_Mute 0x1e
194#define AC97_General_Purpose 0x20
195#define AC97_3D_Control 0x22
196#define AC97_AC_97_RESERVED 0x24
197#define AC97_Powerdown_Ctrl_Stat 0x26
198#define AC97_Extended_Audio_ID 0x28
199#define AC97_Extended_Audio_Ctrl_Stat 0x2a
200#define AC97_PCM_Front_DAC_Rate 0x2c
201#define AC97_PCM_Surround_DAC_Rate 0x2e
202#define AC97_PCM_LFE_DAC_Rate 0x30
203#define AC97_PCM_LR_ADC_Rate 0x32
204#define AC97_MIC_ADC_Rate 0x34
205#define AC97_6Ch_Vol_C_LFE_Mute 0x36
206#define AC97_6Ch_Vol_L_R_Surround_Mute 0x38
207#define AC97_Vendor_Reserved 0x58
208#define AC97_AD_Misc 0x76
209#define AC97_Vendor_ID1 0x7c
210#define AC97_Vendor_ID2 0x7e
211/** @} */
212
213/** @name Analog Devices miscellaneous regiter bits used in AD1980.
214 * @{ */
215#define AC97_AD_MISC_LOSEL RT_BIT(5) /**< Surround (rear) goes to line out outputs. */
216#define AC97_AD_MISC_HPSEL RT_BIT(10) /**< PCM (front) goes to headphone outputs. */
217/** @} */
218
219
220/** @name BUP flag values.
221 * @{ */
222#define BUP_SET RT_BIT_32(0)
223#define BUP_LAST RT_BIT_32(1)
224/** @} */
225
226/** @name AC'97 source indices.
227 * @note The order of these indices is fixed (also applies for saved states) for
228 * the moment. So make sure you know what you're done when altering this!
229 * @{
230 */
231#define AC97SOUNDSOURCE_PI_INDEX 0 /**< PCM in */
232#define AC97SOUNDSOURCE_PO_INDEX 1 /**< PCM out */
233#define AC97SOUNDSOURCE_MC_INDEX 2 /**< Mic in */
234#define AC97SOUNDSOURCE_MAX 3 /**< Max sound sources. */
235/** @} */
236
237/** Port number (offset into NABM BAR) to stream index. */
238#define AC97_PORT2IDX(a_idx) ( ((a_idx) >> 4) & 3 )
239/** Port number (offset into NABM BAR) to stream index, but no masking. */
240#define AC97_PORT2IDX_UNMASKED(a_idx) ( ((a_idx) >> 4) )
241
242/** @name Stream offsets
243 * @{ */
244#define AC97_NABM_OFF_BDBAR 0x0 /**< Buffer Descriptor Base Address */
245#define AC97_NABM_OFF_CIV 0x4 /**< Current Index Value */
246#define AC97_NABM_OFF_LVI 0x5 /**< Last Valid Index */
247#define AC97_NABM_OFF_SR 0x6 /**< Status Register */
248#define AC97_NABM_OFF_PICB 0x8 /**< Position in Current Buffer */
249#define AC97_NABM_OFF_PIV 0xa /**< Prefetched Index Value */
250#define AC97_NABM_OFF_CR 0xb /**< Control Register */
251#define AC97_NABM_OFF_MASK 0xf /**< Mask for getting the the per-stream register. */
252/** @} */
253
254
255/** @name PCM in NABM BAR registers (0x00..0x0f).
256 * @{ */
257#define PI_BDBAR (AC97SOUNDSOURCE_PI_INDEX * 0x10 + 0x0) /**< PCM in: Buffer Descriptor Base Address */
258#define PI_CIV (AC97SOUNDSOURCE_PI_INDEX * 0x10 + 0x4) /**< PCM in: Current Index Value */
259#define PI_LVI (AC97SOUNDSOURCE_PI_INDEX * 0x10 + 0x5) /**< PCM in: Last Valid Index */
260#define PI_SR (AC97SOUNDSOURCE_PI_INDEX * 0x10 + 0x6) /**< PCM in: Status Register */
261#define PI_PICB (AC97SOUNDSOURCE_PI_INDEX * 0x10 + 0x8) /**< PCM in: Position in Current Buffer */
262#define PI_PIV (AC97SOUNDSOURCE_PI_INDEX * 0x10 + 0xa) /**< PCM in: Prefetched Index Value */
263#define PI_CR (AC97SOUNDSOURCE_PI_INDEX * 0x10 + 0xb) /**< PCM in: Control Register */
264/** @} */
265
266/** @name PCM out NABM BAR registers (0x10..0x1f).
267 * @{ */
268#define PO_BDBAR (AC97SOUNDSOURCE_PO_INDEX * 0x10 + 0x0) /**< PCM out: Buffer Descriptor Base Address */
269#define PO_CIV (AC97SOUNDSOURCE_PO_INDEX * 0x10 + 0x4) /**< PCM out: Current Index Value */
270#define PO_LVI (AC97SOUNDSOURCE_PO_INDEX * 0x10 + 0x5) /**< PCM out: Last Valid Index */
271#define PO_SR (AC97SOUNDSOURCE_PO_INDEX * 0x10 + 0x6) /**< PCM out: Status Register */
272#define PO_PICB (AC97SOUNDSOURCE_PO_INDEX * 0x10 + 0x8) /**< PCM out: Position in Current Buffer */
273#define PO_PIV (AC97SOUNDSOURCE_PO_INDEX * 0x10 + 0xa) /**< PCM out: Prefetched Index Value */
274#define PO_CR (AC97SOUNDSOURCE_PO_INDEX * 0x10 + 0xb) /**< PCM out: Control Register */
275/** @} */
276
277/** @name Mic in NABM BAR registers (0x20..0x2f).
278 * @{ */
279#define MC_BDBAR (AC97SOUNDSOURCE_MC_INDEX * 0x10 + 0x0) /**< PCM in: Buffer Descriptor Base Address */
280#define MC_CIV (AC97SOUNDSOURCE_MC_INDEX * 0x10 + 0x4) /**< PCM in: Current Index Value */
281#define MC_LVI (AC97SOUNDSOURCE_MC_INDEX * 0x10 + 0x5) /**< PCM in: Last Valid Index */
282#define MC_SR (AC97SOUNDSOURCE_MC_INDEX * 0x10 + 0x6) /**< PCM in: Status Register */
283#define MC_PICB (AC97SOUNDSOURCE_MC_INDEX * 0x10 + 0x8) /**< PCM in: Position in Current Buffer */
284#define MC_PIV (AC97SOUNDSOURCE_MC_INDEX * 0x10 + 0xa) /**< PCM in: Prefetched Index Value */
285#define MC_CR (AC97SOUNDSOURCE_MC_INDEX * 0x10 + 0xb) /**< PCM in: Control Register */
286/** @} */
287
288/** @name Misc NABM BAR registers.
289 * @{ */
290/** NABMBAR: Global Control Register.
291 * @note This is kind of in the MIC IN area. */
292#define AC97_GLOB_CNT 0x2c
293/** NABMBAR: Global Status. */
294#define AC97_GLOB_STA 0x30
295/** Codec Access Semaphore Register. */
296#define AC97_CAS 0x34
297/** @} */
298
299
300/*********************************************************************************************************************************
301* Structures and Typedefs *
302*********************************************************************************************************************************/
303/** The ICH AC'97 (Intel) controller (shared). */
304typedef struct AC97STATE *PAC97STATE;
305/** The ICH AC'97 (Intel) controller (ring-3). */
306typedef struct AC97STATER3 *PAC97STATER3;
307
308/**
309 * Buffer Descriptor List Entry (BDLE).
310 *
311 * (See section 3.2.1 in Intel document number 252751-001, or section 1.2.2.1 in
312 * Intel document number 302349-003.)
313 */
314typedef struct AC97BDLE
315{
316 /** Location of data buffer (bits 31:1). */
317 uint32_t addr;
318 /** Flags (bits 31 + 30) and length (bits 15:0) of data buffer (in audio samples).
319 * @todo split up into two 16-bit fields. */
320 uint32_t ctl_len;
321} AC97BDLE;
322AssertCompileSize(AC97BDLE, 8);
323/** Pointer to BDLE. */
324typedef AC97BDLE *PAC97BDLE;
325
326/**
327 * Bus master register set for an audio stream.
328 *
329 * (See section 16.2 in Intel document 301473-002, or section 2.2 in Intel
330 * document 302349-003.)
331 */
332typedef struct AC97BMREGS
333{
334 uint32_t bdbar; /**< rw 0, Buffer Descriptor List: BAR (Base Address Register). */
335 uint8_t civ; /**< ro 0, Current index value. */
336 uint8_t lvi; /**< rw 0, Last valid index. */
337 uint16_t sr; /**< rw 1, Status register. */
338 uint16_t picb; /**< ro 0, Position in current buffer (samples left to process). */
339 uint8_t piv; /**< ro 0, Prefetched index value. */
340 uint8_t cr; /**< rw 0, Control register. */
341 int32_t bd_valid; /**< Whether current BDLE is initialized or not. */
342 AC97BDLE bd; /**< Current Buffer Descriptor List Entry (BDLE). */
343} AC97BMREGS;
344AssertCompileSizeAlignment(AC97BMREGS, 8);
345/** Pointer to the BM registers of an audio stream. */
346typedef AC97BMREGS *PAC97BMREGS;
347
348/**
349 * The internal state of an AC'97 stream.
350 */
351typedef struct AC97STREAMSTATE
352{
353 /** Critical section for this stream. */
354 RTCRITSECT CritSect;
355 /** Circular buffer (FIFO) for holding DMA'ed data. */
356 R3PTRTYPE(PRTCIRCBUF) pCircBuf;
357#if HC_ARCH_BITS == 32
358 uint32_t Padding;
359#endif
360 /** Current circular buffer read offset (for tracing & logging). */
361 uint64_t offRead;
362 /** Current circular buffer write offset (for tracing & logging). */
363 uint64_t offWrite;
364 /** The stream's current configuration. */
365 PDMAUDIOSTREAMCFG Cfg; //+108
366 /** Timestamp of the last DMA data transfer. */
367 uint64_t tsTransferLast;
368 /** Timestamp of the next DMA data transfer.
369 * Next for determining the next scheduling window.
370 * Can be 0 if no next transfer is scheduled. */
371 uint64_t tsTransferNext;
372 /** Transfer chunk size (in bytes) of a transfer period. */
373 uint32_t cbTransferChunk;
374 /** The stream's timer Hz rate.
375 * This value can can be different from the device's default Hz rate,
376 * depending on the rate the stream expects (e.g. for 5.1 speaker setups).
377 * Set in R3StreamInit(). */
378 uint16_t uTimerHz;
379 /** Set if we've registered the asynchronous update job. */
380 bool fRegisteredAsyncUpdateJob;
381 /** Input streams only: Set when we switch from feeding the guest silence and
382 * commits to proving actual audio input bytes. */
383 bool fInputPreBuffered;
384 /** This is ZERO if stream setup succeeded, otherwise it's the RTTimeNanoTS() at
385 * which to retry setting it up. The latter applies only to same
386 * parameters. */
387 uint64_t nsRetrySetup;
388 /** (Virtual) clock ticks per transfer. */
389 uint64_t cTransferTicks;
390 /** Timestamp (in ns) of last stream update. */
391 uint64_t tsLastUpdateNs;
392
393 /** Size of the DMA buffer (pCircBuf) in bytes. */
394 uint32_t StatDmaBufSize;
395 /** Number of used bytes in the DMA buffer (pCircBuf). */
396 uint32_t StatDmaBufUsed;
397 /** Counter for all under/overflows problems. */
398 STAMCOUNTER StatDmaFlowProblems;
399 /** Counter for unresovled under/overflows problems. */
400 STAMCOUNTER StatDmaFlowErrors;
401 /** Number of bytes involved in unresolved flow errors. */
402 STAMCOUNTER StatDmaFlowErrorBytes;
403} AC97STREAMSTATE;
404AssertCompileSizeAlignment(AC97STREAMSTATE, 8);
405/** Pointer to internal state of an AC'97 stream. */
406typedef AC97STREAMSTATE *PAC97STREAMSTATE;
407
408/**
409 * Runtime configurable debug stuff for an AC'97 stream.
410 */
411typedef struct AC97STREAMDEBUGRT
412{
413 /** Whether debugging is enabled or not. */
414 bool fEnabled;
415 uint8_t Padding[7];
416 /** File for dumping stream reads / writes.
417 * For input streams, this dumps data being written to the device FIFO,
418 * whereas for output streams this dumps data being read from the device FIFO. */
419 R3PTRTYPE(PAUDIOHLPFILE) pFileStream;
420 /** File for dumping DMA reads / writes.
421 * For input streams, this dumps data being written to the device DMA,
422 * whereas for output streams this dumps data being read from the device DMA. */
423 R3PTRTYPE(PAUDIOHLPFILE) pFileDMA;
424} AC97STREAMDEBUGRT;
425
426/**
427 * Debug stuff for an AC'97 stream.
428 */
429typedef struct AC97STREAMDEBUG
430{
431 /** Runtime debug stuff. */
432 AC97STREAMDEBUGRT Runtime;
433} AC97STREAMDEBUG;
434
435/**
436 * The shared AC'97 stream state.
437 */
438typedef struct AC97STREAM
439{
440 /** Stream number (SDn). */
441 uint8_t u8SD;
442 uint8_t abPadding0[7];
443 /** Bus master registers of this stream. */
444 AC97BMREGS Regs;
445 /** The timer for pumping data thru the attached LUN drivers. */
446 TMTIMERHANDLE hTimer;
447} AC97STREAM;
448AssertCompileSizeAlignment(AC97STREAM, 8);
449/** Pointer to a shared AC'97 stream state. */
450typedef AC97STREAM *PAC97STREAM;
451
452
453/**
454 * The ring-3 AC'97 stream state.
455 */
456typedef struct AC97STREAMR3
457{
458 /** Stream number (SDn). */
459 uint8_t u8SD;
460 uint8_t abPadding0[7];
461 /** Internal state of this stream. */
462 AC97STREAMSTATE State;
463 /** Debug stuff. */
464 AC97STREAMDEBUG Dbg;
465} AC97STREAMR3;
466AssertCompileSizeAlignment(AC97STREAMR3, 8);
467/** Pointer to an AC'97 stream state for ring-3. */
468typedef AC97STREAMR3 *PAC97STREAMR3;
469
470
471/**
472 * A driver stream (host backend).
473 *
474 * Each driver has its own instances of audio mixer streams, which then
475 * can go into the same (or even different) audio mixer sinks.
476 */
477typedef struct AC97DRIVERSTREAM
478{
479 /** Associated mixer stream handle. */
480 R3PTRTYPE(PAUDMIXSTREAM) pMixStrm;
481} AC97DRIVERSTREAM;
482/** Pointer to a driver stream. */
483typedef AC97DRIVERSTREAM *PAC97DRIVERSTREAM;
484
485/**
486 * A host backend driver (LUN).
487 */
488typedef struct AC97DRIVER
489{
490 /** Node for storing this driver in our device driver list of AC97STATE. */
491 RTLISTNODER3 Node;
492 /** LUN # to which this driver has been assigned. */
493 uint8_t uLUN;
494 /** Whether this driver is in an attached state or not. */
495 bool fAttached;
496 uint8_t abPadding[6];
497 /** Pointer to the description string passed to PDMDevHlpDriverAttach(). */
498 R3PTRTYPE(char *) pszDesc;
499 /** Pointer to attached driver base interface. */
500 R3PTRTYPE(PPDMIBASE) pDrvBase;
501 /** Audio connector interface to the underlying host backend. */
502 R3PTRTYPE(PPDMIAUDIOCONNECTOR) pConnector;
503 /** Driver stream for line input. */
504 AC97DRIVERSTREAM LineIn;
505 /** Driver stream for mic input. */
506 AC97DRIVERSTREAM MicIn;
507 /** Driver stream for output. */
508 AC97DRIVERSTREAM Out;
509} AC97DRIVER;
510/** Pointer to a host backend driver (LUN). */
511typedef AC97DRIVER *PAC97DRIVER;
512
513/**
514 * Debug settings.
515 */
516typedef struct AC97STATEDEBUG
517{
518 /** Whether debugging is enabled or not. */
519 bool fEnabled;
520 bool afAlignment[7];
521 /** Path where to dump the debug output to.
522 * Can be NULL, in which the system's temporary directory will be used then. */
523 R3PTRTYPE(char *) pszOutPath;
524} AC97STATEDEBUG;
525
526
527/* Codec models. */
528typedef enum AC97CODEC
529{
530 AC97CODEC_INVALID = 0, /**< Customary illegal zero value. */
531 AC97CODEC_STAC9700, /**< SigmaTel STAC9700 */
532 AC97CODEC_AD1980, /**< Analog Devices AD1980 */
533 AC97CODEC_AD1981B, /**< Analog Devices AD1981B */
534 AC97CODEC_32BIT_HACK = 0x7fffffff
535} AC97CODEC;
536
537
538/**
539 * The shared AC'97 device state.
540 */
541typedef struct AC97STATE
542{
543 /** Critical section protecting the AC'97 state. */
544 PDMCRITSECT CritSect;
545 /** Global Control (Bus Master Control Register). */
546 uint32_t glob_cnt;
547 /** Global Status (Bus Master Control Register). */
548 uint32_t glob_sta;
549 /** Codec Access Semaphore Register (Bus Master Control Register). */
550 uint32_t cas;
551 uint32_t last_samp;
552 uint8_t mixer_data[256];
553 /** Array of AC'97 streams (parallel to AC97STATER3::aStreams). */
554 AC97STREAM aStreams[AC97_MAX_STREAMS];
555 /** The device timer Hz rate. Defaults to AC97_TIMER_HZ_DEFAULT_DEFAULT. */
556 uint16_t uTimerHz;
557 /** Config: Internal input DMA buffer size override, specified in milliseconds.
558 * Zero means default size according to buffer and stream config.
559 * @sa BufSizeInMs config value. */
560 uint16_t cMsCircBufIn;
561 /** Config: Internal output DMA buffer size override, specified in milliseconds.
562 * Zero means default size according to buffer and stream config.
563 * @sa BufSizeOutMs config value. */
564 uint16_t cMsCircBufOut;
565 uint16_t au16Padding1[1];
566 uint8_t silence[128];
567 uint32_t bup_flag;
568 /** Codec model. */
569 AC97CODEC enmCodecModel;
570
571 /** PCI region \#0: NAM I/O ports. */
572 IOMIOPORTHANDLE hIoPortsNam;
573 /** PCI region \#0: NANM I/O ports. */
574 IOMIOPORTHANDLE hIoPortsNabm;
575
576 STAMCOUNTER StatUnimplementedNabmReads;
577 STAMCOUNTER StatUnimplementedNabmWrites;
578#ifdef VBOX_WITH_STATISTICS
579 STAMPROFILE StatTimer;
580 STAMPROFILE StatIn;
581 STAMPROFILE StatOut;
582 STAMCOUNTER StatBytesRead;
583 STAMCOUNTER StatBytesWritten;
584#endif
585} AC97STATE;
586AssertCompileMemberAlignment(AC97STATE, aStreams, 8);
587AssertCompileMemberAlignment(AC97STATE, StatUnimplementedNabmReads, 8);
588#ifdef VBOX_WITH_STATISTICS
589AssertCompileMemberAlignment(AC97STATE, StatTimer, 8);
590AssertCompileMemberAlignment(AC97STATE, StatBytesRead, 8);
591AssertCompileMemberAlignment(AC97STATE, StatBytesWritten, 8);
592#endif
593
594
595/**
596 * The ring-3 AC'97 device state.
597 */
598typedef struct AC97STATER3
599{
600 /** Array of AC'97 streams (parallel to AC97STATE:aStreams). */
601 AC97STREAMR3 aStreams[AC97_MAX_STREAMS];
602 /** R3 pointer to the device instance. */
603 PPDMDEVINSR3 pDevIns;
604 /** List of associated LUN drivers (AC97DRIVER). */
605 RTLISTANCHORR3 lstDrv;
606 /** The device's software mixer. */
607 R3PTRTYPE(PAUDIOMIXER) pMixer;
608 /** Audio sink for PCM output. */
609 R3PTRTYPE(PAUDMIXSINK) pSinkOut;
610 /** Audio sink for line input. */
611 R3PTRTYPE(PAUDMIXSINK) pSinkLineIn;
612 /** Audio sink for microphone input. */
613 R3PTRTYPE(PAUDMIXSINK) pSinkMicIn;
614 /** The base interface for LUN\#0. */
615 PDMIBASE IBase;
616 /** Debug settings. */
617 AC97STATEDEBUG Dbg;
618} AC97STATER3;
619AssertCompileMemberAlignment(AC97STATER3, aStreams, 8);
620/** Pointer to the ring-3 AC'97 device state. */
621typedef AC97STATER3 *PAC97STATER3;
622
623
624/**
625 * Acquires the AC'97 lock.
626 */
627#define DEVAC97_LOCK(a_pDevIns, a_pThis) \
628 do { \
629 int rcLock = PDMDevHlpCritSectEnter((a_pDevIns), &(a_pThis)->CritSect, VERR_IGNORED); \
630 AssertRC(rcLock); \
631 } while (0)
632
633/**
634 * Acquires the AC'97 lock or returns.
635 */
636# define DEVAC97_LOCK_RETURN(a_pDevIns, a_pThis, a_rcBusy) \
637 do { \
638 int rcLock = PDMDevHlpCritSectEnter((a_pDevIns), &(a_pThis)->CritSect, a_rcBusy); \
639 if (rcLock == VINF_SUCCESS) \
640 break; \
641 AssertRC(rcLock); \
642 return rcLock; \
643 } while (0)
644
645/** Retrieves an attribute from a specific audio stream in RC. */
646#define DEVAC97_CTX_SUFF_SD(a_Var, a_SD) CTX_SUFF(a_Var)[a_SD]
647
648/**
649 * Releases the AC'97 lock.
650 */
651#define DEVAC97_UNLOCK(a_pDevIns, a_pThis) \
652 do { PDMDevHlpCritSectLeave((a_pDevIns), &(a_pThis)->CritSect); } while (0)
653
654/**
655 * Acquires the TM lock and AC'97 lock, returns on failure.
656 *
657 * @todo r=bird: Isn't this overkill for ring-0, only ring-3 access the timer
658 * from what I can tell (ichac97R3StreamTransferCalcNext,
659 * ichac97R3TimerSet, timer callback and state load).
660 */
661#define DEVAC97_LOCK_BOTH_RETURN(a_pDevIns, a_pThis, a_pStream, a_rcBusy) \
662 do { \
663 VBOXSTRICTRC rcLock = PDMDevHlpTimerLockClock2((a_pDevIns), (a_pStream)->hTimer, &(a_pThis)->CritSect, (a_rcBusy)); \
664 if (RT_LIKELY(rcLock == VINF_SUCCESS)) \
665 { /* likely */ } \
666 else \
667 { \
668 AssertRC(VBOXSTRICTRC_VAL(rcLock)); \
669 return rcLock; \
670 } \
671 } while (0)
672
673/**
674 * Releases the AC'97 lock and TM lock.
675 */
676#define DEVAC97_UNLOCK_BOTH(a_pDevIns, a_pThis, a_pStream) \
677 PDMDevHlpTimerUnlockClock2((a_pDevIns), (a_pStream)->hTimer, &(a_pThis)->CritSect)
678
679#ifndef VBOX_DEVICE_STRUCT_TESTCASE
680
681
682/*********************************************************************************************************************************
683* Internal Functions *
684*********************************************************************************************************************************/
685static void ichac97StreamUpdateSR(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, uint32_t new_sr);
686static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t uMixerIdx);
687#ifdef IN_RING3
688DECLINLINE(void) ichac97R3StreamLock(PAC97STREAMR3 pStreamCC);
689DECLINLINE(void) ichac97R3StreamUnlock(PAC97STREAMR3 pStreamCC);
690static void ichac97R3DbgPrintBdl(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream,
691 PCDBGFINFOHLP pHlp, const char *pszPrefix);
692static DECLCALLBACK(void) ichac97R3Reset(PPDMDEVINS pDevIns);
693#endif
694
695
696/*********************************************************************************************************************************
697* Global Variables *
698*********************************************************************************************************************************/
699#ifdef IN_RING3
700/** NABM I/O port descriptions. */
701static const IOMIOPORTDESC g_aNabmPorts[] =
702{
703 { "PCM IN - BDBAR", "PCM IN - BDBAR", NULL, NULL },
704 { "", NULL, NULL, NULL },
705 { "", NULL, NULL, NULL },
706 { "", NULL, NULL, NULL },
707 { "PCM IN - CIV", "PCM IN - CIV", NULL, NULL },
708 { "PCM IN - LVI", "PCM IN - LIV", NULL, NULL },
709 { "PCM IN - SR", "PCM IN - SR", NULL, NULL },
710 { "", NULL, NULL, NULL },
711 { "PCM IN - PICB", "PCM IN - PICB", NULL, NULL },
712 { "", NULL, NULL, NULL },
713 { "PCM IN - PIV", "PCM IN - PIV", NULL, NULL },
714 { "PCM IN - CR", "PCM IN - CR", NULL, NULL },
715 { "", NULL, NULL, NULL },
716 { "", NULL, NULL, NULL },
717 { "", NULL, NULL, NULL },
718 { "", NULL, NULL, NULL },
719
720 { "PCM OUT - BDBAR", "PCM OUT - BDBAR", NULL, NULL },
721 { "", NULL, NULL, NULL },
722 { "", NULL, NULL, NULL },
723 { "", NULL, NULL, NULL },
724 { "PCM OUT - CIV", "PCM OUT - CIV", NULL, NULL },
725 { "PCM OUT - LVI", "PCM OUT - LIV", NULL, NULL },
726 { "PCM OUT - SR", "PCM OUT - SR", NULL, NULL },
727 { "", NULL, NULL, NULL },
728 { "PCM OUT - PICB", "PCM OUT - PICB", NULL, NULL },
729 { "", NULL, NULL, NULL },
730 { "PCM OUT - PIV", "PCM OUT - PIV", NULL, NULL },
731 { "PCM OUT - CR", "PCM IN - CR", NULL, NULL },
732 { "", NULL, NULL, NULL },
733 { "", NULL, NULL, NULL },
734 { "", NULL, NULL, NULL },
735 { "", NULL, NULL, NULL },
736
737 { "MIC IN - BDBAR", "MIC IN - BDBAR", NULL, NULL },
738 { "", NULL, NULL, NULL },
739 { "", NULL, NULL, NULL },
740 { "", NULL, NULL, NULL },
741 { "MIC IN - CIV", "MIC IN - CIV", NULL, NULL },
742 { "MIC IN - LVI", "MIC IN - LIV", NULL, NULL },
743 { "MIC IN - SR", "MIC IN - SR", NULL, NULL },
744 { "", NULL, NULL, NULL },
745 { "MIC IN - PICB", "MIC IN - PICB", NULL, NULL },
746 { "", NULL, NULL, NULL },
747 { "MIC IN - PIV", "MIC IN - PIV", NULL, NULL },
748 { "MIC IN - CR", "MIC IN - CR", NULL, NULL },
749 { "GLOB CNT", "GLOB CNT", NULL, NULL },
750 { "", NULL, NULL, NULL },
751 { "", NULL, NULL, NULL },
752 { "", NULL, NULL, NULL },
753
754 { "GLOB STA", "GLOB STA", NULL, NULL },
755 { "", NULL, NULL, NULL },
756 { "", NULL, NULL, NULL },
757 { "", NULL, NULL, NULL },
758 { "CAS", "CAS", NULL, NULL },
759 { NULL, NULL, NULL, NULL },
760};
761
762/** @name Source indices
763 * @{ */
764# define AC97SOUNDSOURCE_PI_INDEX 0 /**< PCM in */
765# define AC97SOUNDSOURCE_PO_INDEX 1 /**< PCM out */
766# define AC97SOUNDSOURCE_MC_INDEX 2 /**< Mic in */
767# define AC97SOUNDSOURCE_MAX 3 /**< Max sound sources. */
768/** @} */
769
770/** Port number (offset into NABM BAR) to stream index. */
771# define AC97_PORT2IDX(a_idx) ( ((a_idx) >> 4) & 3 )
772/** Port number (offset into NABM BAR) to stream index, but no masking. */
773# define AC97_PORT2IDX_UNMASKED(a_idx) ( ((a_idx) >> 4) )
774
775/** @name Stream offsets
776 * @{ */
777# define AC97_NABM_OFF_BDBAR 0x0 /**< Buffer Descriptor Base Address */
778# define AC97_NABM_OFF_CIV 0x4 /**< Current Index Value */
779# define AC97_NABM_OFF_LVI 0x5 /**< Last Valid Index */
780# define AC97_NABM_OFF_SR 0x6 /**< Status Register */
781# define AC97_NABM_OFF_PICB 0x8 /**< Position in Current Buffer */
782# define AC97_NABM_OFF_PIV 0xa /**< Prefetched Index Value */
783# define AC97_NABM_OFF_CR 0xb /**< Control Register */
784# define AC97_NABM_OFF_MASK 0xf /**< Mask for getting the the per-stream register. */
785/** @} */
786
787#endif /* IN_RING3 */
788
789
790
791static void ichac97WarmReset(PAC97STATE pThis)
792{
793 NOREF(pThis);
794}
795
796static void ichac97ColdReset(PAC97STATE pThis)
797{
798 NOREF(pThis);
799}
800
801
802#ifdef IN_RING3
803
804/**
805 * Returns the audio direction of a specified stream descriptor.
806 *
807 * @return Audio direction.
808 */
809DECLINLINE(PDMAUDIODIR) ichac97R3GetDirFromSD(uint8_t uSD)
810{
811 switch (uSD)
812 {
813 case AC97SOUNDSOURCE_PI_INDEX: return PDMAUDIODIR_IN;
814 case AC97SOUNDSOURCE_PO_INDEX: return PDMAUDIODIR_OUT;
815 case AC97SOUNDSOURCE_MC_INDEX: return PDMAUDIODIR_IN;
816 }
817
818 AssertFailed();
819 return PDMAUDIODIR_UNKNOWN;
820}
821
822
823/**
824 * Retrieves the audio mixer sink of a corresponding AC'97 stream index.
825 *
826 * @returns Pointer to audio mixer sink if found, or NULL if not found / invalid.
827 * @param pThisCC The ring-3 AC'97 state.
828 * @param uIndex Stream index to get audio mixer sink for.
829 */
830DECLINLINE(PAUDMIXSINK) ichac97R3IndexToSink(PAC97STATER3 pThisCC, uint8_t uIndex)
831{
832 switch (uIndex)
833 {
834 case AC97SOUNDSOURCE_PI_INDEX: return pThisCC->pSinkLineIn;
835 case AC97SOUNDSOURCE_PO_INDEX: return pThisCC->pSinkOut;
836 case AC97SOUNDSOURCE_MC_INDEX: return pThisCC->pSinkMicIn;
837 default:
838 AssertMsgFailedReturn(("Wrong index %RU8\n", uIndex), NULL);
839 }
840}
841
842
843/*********************************************************************************************************************************
844* Stream DMA *
845*********************************************************************************************************************************/
846
847/**
848 * Retrieves the available size of (buffered) audio data (in bytes) of a given AC'97 stream.
849 *
850 * @returns Available data (in bytes).
851 * @param pStreamCC The AC'97 stream to retrieve size for (ring-3).
852 */
853DECLINLINE(uint32_t) ichac97R3StreamGetUsed(PAC97STREAMR3 pStreamCC)
854{
855 PRTCIRCBUF const pCircBuf = pStreamCC->State.pCircBuf;
856 if (pCircBuf)
857 return (uint32_t)RTCircBufUsed(pCircBuf);
858 return 0;
859}
860
861
862/**
863 * Retrieves the free size of audio data (in bytes) of a given AC'97 stream.
864 *
865 * @returns Free data (in bytes).
866 * @param pStreamCC AC'97 stream to retrieve size for (ring-3).
867 */
868DECLINLINE(uint32_t) ichac97R3StreamGetFree(PAC97STREAMR3 pStreamCC)
869{
870 PRTCIRCBUF const pCircBuf = pStreamCC->State.pCircBuf;
871 if (pCircBuf)
872 return (uint32_t)RTCircBufFree(pCircBuf);
873 return 0;
874}
875
876
877# if 0 /* Unused */
878static void ichac97R3WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
879{
880 LogFlowFunc(("cbElapsed=%RU32\n", cbElapsed));
881
882 if (!(pThis->bup_flag & BUP_SET))
883 {
884 if (pThis->bup_flag & BUP_LAST)
885 {
886 unsigned int i;
887 uint32_t *p = (uint32_t*)pThis->silence;
888 for (i = 0; i < sizeof(pThis->silence) / 4; i++) /** @todo r=andy Assumes 16-bit samples, stereo. */
889 *p++ = pThis->last_samp;
890 }
891 else
892 RT_ZERO(pThis->silence);
893
894 pThis->bup_flag |= BUP_SET;
895 }
896
897 while (cbElapsed)
898 {
899 uint32_t cbToWrite = RT_MIN(cbElapsed, (uint32_t)sizeof(pThis->silence));
900 uint32_t cbWrittenToStream;
901
902 int rc2 = AudioMixerSinkWrite(pThisCC->pSinkOut, AUDMIXOP_COPY,
903 pThis->silence, cbToWrite, &cbWrittenToStream);
904 if (RT_SUCCESS(rc2))
905 {
906 if (cbWrittenToStream < cbToWrite) /* Lagging behind? */
907 LogFlowFunc(("Warning: Only written %RU32 / %RU32 bytes, expect lags\n", cbWrittenToStream, cbToWrite));
908 }
909
910 /* Always report all data as being written;
911 * backends who were not able to catch up have to deal with it themselves. */
912 Assert(cbElapsed >= cbToWrite);
913 cbElapsed -= cbToWrite;
914 }
915}
916# endif /* Unused */
917
918
919/**
920 * Fetches the next buffer descriptor (BDLE) updating the stream registers.
921 *
922 * This will skip zero length descriptors.
923 *
924 * @returns Zero, or AC97_SR_BCIS if skipped zero length buffer with IOC set.
925 * @param pDevIns The device instance.
926 * @param pStream AC'97 stream to fetch BDLE for.
927 * @param pStreamCC The AC'97 stream, ring-3 state.
928 *
929 * @remarks Updates CIV, PIV, BD and PICB.
930 *
931 * @note Both PIV and CIV will be zero after a stream reset, so the first
932 * time we advance the buffer position afterwards, CIV will remain zero
933 * and PIV becomes 1. Thus we will start processing from BDLE00 and
934 * not BDLE01 as CIV=0 may lead you to think.
935 */
936static uint32_t ichac97R3StreamFetchNextBdle(PPDMDEVINS pDevIns, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)
937{
938 RT_NOREF(pStreamCC);
939 uint32_t fSrBcis = 0;
940
941 /*
942 * Loop for skipping zero length entries.
943 */
944 for (;;)
945 {
946 /* Advance the buffer. */
947 pStream->Regs.civ = pStream->Regs.piv % AC97_MAX_BDLE /* (paranoia) */;
948 pStream->Regs.piv = (pStream->Regs.piv + 1) % AC97_MAX_BDLE;
949
950 /* Load it. */
951 AC97BDLE Bdle = { 0, 0 };
952 PDMDevHlpPCIPhysRead(pDevIns, pStream->Regs.bdbar + pStream->Regs.civ * sizeof(AC97BDLE), &Bdle, sizeof(AC97BDLE));
953 pStream->Regs.bd_valid = 1;
954 pStream->Regs.bd.addr = RT_H2LE_U32(Bdle.addr) & ~3;
955 pStream->Regs.bd.ctl_len = RT_H2LE_U32(Bdle.ctl_len);
956 pStream->Regs.picb = pStream->Regs.bd.ctl_len & AC97_BD_LEN_MASK;
957
958 LogFlowFunc(("BDLE%02u: %#RX32 L %#x / LB %#x, ctl=%#06x%s%s\n",
959 pStream->Regs.civ, pStream->Regs.bd.addr, pStream->Regs.bd.ctl_len & AC97_BD_LEN_MASK,
960 (pStream->Regs.bd.ctl_len & AC97_BD_LEN_MASK) * PDMAudioPropsSampleSize(&pStreamCC->State.Cfg.Props),
961 pStream->Regs.bd.ctl_len >> 16,
962 pStream->Regs.bd.ctl_len & AC97_BD_IOC ? " ioc" : "",
963 pStream->Regs.bd.ctl_len & AC97_BD_BUP ? " bup" : ""));
964
965 /* Complain about any reserved bits set in CTL and ADDR: */
966 ASSERT_GUEST_MSG(!(pStream->Regs.bd.ctl_len & AC97_BD_LEN_CTL_MBZ),
967 ("Reserved bits set: %#RX32\n", pStream->Regs.bd.ctl_len));
968 ASSERT_GUEST_MSG(!(RT_H2LE_U32(Bdle.addr) & 3),
969 ("Reserved addr bits set: %#RX32\n", RT_H2LE_U32(Bdle.addr) ));
970
971 /* If the length is non-zero or if we've reached LVI, we're done regardless
972 of what's been loaded. Otherwise, we skip zero length buffers. */
973 if (pStream->Regs.picb)
974 break;
975 if (pStream->Regs.civ == (pStream->Regs.lvi % AC97_MAX_BDLE /* (paranoia) */))
976 {
977 LogFunc(("BDLE%02u is zero length! Can't skip (CIV=LVI). %#RX32 %#RX32\n", pStream->Regs.civ, Bdle.addr, Bdle.ctl_len));
978 break;
979 }
980 LogFunc(("BDLE%02u is zero length! Skipping. %#RX32 %#RX32\n", pStream->Regs.civ, Bdle.addr, Bdle.ctl_len));
981
982 /* If the buffer has IOC set, make sure it's triggered by the caller. */
983 if (pStream->Regs.bd.ctl_len & AC97_BD_IOC)
984 fSrBcis |= AC97_SR_BCIS;
985 }
986
987 /* 1.2.4.2 PCM Buffer Restrictions (in 302349-003) - #1 */
988 ASSERT_GUEST_MSG(!(pStream->Regs.picb & 1),
989 ("Odd lengths buffers are not allowed: %#x (%d) samples\n", pStream->Regs.picb, pStream->Regs.picb));
990
991 /* 1.2.4.2 PCM Buffer Restrictions (in 302349-003) - #2 */
992 ASSERT_GUEST_MSG(pStream->Regs.picb > 0, ("Zero length buffers not allowed to terminate list (LVI=%u CIV=%u)\n",
993 pStream->Regs.lvi, pStream->Regs.civ));
994
995 return fSrBcis;
996}
997
998
999/**
1000 * Transfers data of an AC'97 stream according to its usage (input / output).
1001 *
1002 * For an SDO (output) stream this means reading DMA data from the device to
1003 * the AC'97 stream's internal FIFO buffer.
1004 *
1005 * For an SDI (input) stream this is reading audio data from the AC'97 stream's
1006 * internal FIFO buffer and writing it as DMA data to the device.
1007 *
1008 * @returns VBox status code.
1009 * @param pDevIns The device instance.
1010 * @param pThis The shared AC'97 state.
1011 * @param pStream The AC'97 stream to update (shared).
1012 * @param pStreamCC The AC'97 stream to update (ring-3).
1013 * @param cbToProcessMax Maximum of data (in bytes) to process.
1014 * @param fWriteSilence Whether to write silence if this is an input
1015 * stream (done while waiting for backend to get
1016 * going).
1017 * @param fInput Set if input, clear if output.
1018 */
1019static int ichac97R3StreamTransfer(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream,
1020 PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax, bool fWriteSilence, bool fInput)
1021{
1022 if (RT_LIKELY(cbToProcessMax > 0))
1023 Assert(PDMAudioPropsIsSizeAligned(&pStreamCC->State.Cfg.Props, cbToProcessMax));
1024 else
1025 return VINF_SUCCESS;
1026
1027 ichac97R3StreamLock(pStreamCC);
1028
1029 PAC97BMREGS pRegs = &pStream->Regs;
1030
1031 if (!(pRegs->sr & AC97_SR_DCH)) /* Controller halted? */
1032 { /* not halted - likely */ }
1033 else
1034 {
1035 if (pRegs->cr & AC97_CR_RPBM) /* Bus master operation starts. */
1036 {
1037 switch (pStream->u8SD)
1038 {
1039 case AC97SOUNDSOURCE_PO_INDEX:
1040 /*ichac97R3WriteBUP(pThis, cbToProcess);*/
1041 break;
1042
1043 default:
1044 break;
1045 }
1046 }
1047
1048 ichac97R3StreamUnlock(pStreamCC);
1049 return VINF_SUCCESS;
1050 }
1051
1052 /* BCIS flag still set? Skip iteration. */
1053/** @todo combine with the above test. */
1054 if (!(pRegs->sr & AC97_SR_BCIS))
1055 { /* likely */ }
1056 else
1057 {
1058 /** @todo counter */
1059 Log3Func(("[SD%RU8] BCIS set\n", pStream->u8SD));
1060
1061 ichac97R3StreamUnlock(pStreamCC);
1062 return VINF_SUCCESS;
1063 }
1064
1065 uint32_t cbLeft = RT_MIN((uint32_t)(pRegs->picb << 1), cbToProcessMax); /** @todo r=andy Assumes 16bit samples. */
1066 uint32_t cbProcessedTotal = 0;
1067
1068 PRTCIRCBUF pCircBuf = pStreamCC->State.pCircBuf;
1069 AssertReturnStmt(pCircBuf, ichac97R3StreamUnlock(pStreamCC), VINF_SUCCESS);
1070
1071 int rc = VINF_SUCCESS;
1072
1073 Log3Func(("[SD%RU8] cbToProcessMax=%RU32, cbLeft=%RU32\n", pStream->u8SD, cbToProcessMax, cbLeft));
1074
1075 while (cbLeft)
1076 {
1077 if (!pRegs->picb) /* Got a new buffer descriptor, that is, the position is 0? */
1078 {
1079 Log3Func(("Fresh buffer descriptor %RU8 is empty, addr=%#x, len=%#x, skipping\n",
1080 pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len));
1081 if (pRegs->civ == pRegs->lvi)
1082 {
1083 pRegs->sr |= AC97_SR_DCH; /** @todo r=andy Also set CELV? */
1084 pThis->bup_flag = 0;
1085
1086 rc = VINF_EOF;
1087 break;
1088 }
1089
1090 pRegs->sr &= ~AC97_SR_CELV;
1091 if (ichac97R3StreamFetchNextBdle(pDevIns, pStream, pStreamCC))
1092 ichac97StreamUpdateSR(pDevIns, pThis, pStream, pRegs->sr | AC97_SR_BCIS);
1093 continue;
1094 }
1095
1096 uint32_t cbChunk = cbLeft;
1097
1098 /*
1099 * Output.
1100 */
1101 if (!fInput)
1102 {
1103 void *pvDst = NULL;
1104 size_t cbDst = 0;
1105 RTCircBufAcquireWriteBlock(pCircBuf, cbChunk, &pvDst, &cbDst);
1106
1107 if (cbDst)
1108 {
1109 int rc2 = PDMDevHlpPCIPhysRead(pDevIns, pRegs->bd.addr, pvDst, cbDst);
1110 AssertRC(rc2);
1111
1112 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))
1113 { /* likely */ }
1114 else
1115 AudioHlpFileWrite(pStreamCC->Dbg.Runtime.pFileDMA, pvDst, cbDst, 0 /* fFlags */);
1116 }
1117
1118 RTCircBufReleaseWriteBlock(pCircBuf, cbDst);
1119
1120 cbChunk = (uint32_t)cbDst; /* Update the current chunk size to what really has been written. */
1121 }
1122 /*
1123 * Input.
1124 */
1125 else
1126 {
1127 if (!fWriteSilence)
1128 {
1129 void *pvSrc = NULL;
1130 size_t cbSrc = 0;
1131 RTCircBufAcquireReadBlock(pCircBuf, cbChunk, &pvSrc, &cbSrc);
1132
1133 if (cbSrc)
1134 {
1135 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, pvSrc, cbSrc);
1136 AssertRC(rc2);
1137
1138 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))
1139 { /* likely */ }
1140 else
1141 AudioHlpFileWrite(pStreamCC->Dbg.Runtime.pFileDMA, pvSrc, cbSrc, 0 /* fFlags */);
1142 }
1143
1144 RTCircBufReleaseReadBlock(pCircBuf, cbSrc);
1145
1146 cbChunk = (uint32_t)cbSrc; /* Update the current chunk size to what really has been read. */
1147 }
1148 else
1149 {
1150 /* Since the format is signed 16-bit or 32-bit integer samples, we can
1151 use g_abRTZero64K as source and avoid some unnecessary bzero() work. */
1152 cbChunk = RT_MIN(cbChunk, sizeof(g_abRTZero64K));
1153 cbChunk = PDMAudioPropsFloorBytesToFrame(&pStreamCC->State.Cfg.Props, cbChunk);
1154
1155 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, g_abRTZero64K, cbChunk);
1156 AssertRC(rc2);
1157 }
1158 }
1159
1160 if (cbChunk)
1161 {
1162 Assert(PDMAudioPropsIsSizeAligned(&pStreamCC->State.Cfg.Props, cbChunk));
1163 Assert(cbChunk <= cbLeft);
1164
1165 cbProcessedTotal += cbChunk;
1166 Assert(cbProcessedTotal <= cbToProcessMax);
1167 cbLeft -= cbChunk;
1168 pRegs->picb -= (cbChunk >> 1); /** @todo r=andy Assumes 16bit samples. */
1169 pRegs->bd.addr += cbChunk;
1170 }
1171
1172 LogFlowFunc(("[SD%RU8] cbChunk=%RU32, cbLeft=%RU32, cbTotal=%RU32, rc=%Rrc\n",
1173 pStream->u8SD, cbChunk, cbLeft, cbProcessedTotal, rc));
1174
1175 if (!pRegs->picb)
1176 {
1177 uint32_t new_sr = pRegs->sr & ~AC97_SR_CELV;
1178
1179 if (pRegs->bd.ctl_len & AC97_BD_IOC)
1180 {
1181 new_sr |= AC97_SR_BCIS;
1182 }
1183
1184 if (pRegs->civ == pRegs->lvi)
1185 {
1186 /* Did we run out of data? */
1187 LogFunc(("Underrun CIV (%RU8) == LVI (%RU8)\n", pRegs->civ, pRegs->lvi));
1188
1189 new_sr |= AC97_SR_LVBCI | AC97_SR_DCH | AC97_SR_CELV;
1190 pThis->bup_flag = (pRegs->bd.ctl_len & AC97_BD_BUP) ? BUP_LAST : 0;
1191
1192 rc = VINF_EOF;
1193 }
1194 else
1195 new_sr |= ichac97R3StreamFetchNextBdle(pDevIns, pStream, pStreamCC);
1196
1197 ichac97StreamUpdateSR(pDevIns, pThis, pStream, new_sr);
1198 }
1199
1200 /* All data processed? */
1201 if (rc == VINF_EOF)
1202 break;
1203 }
1204
1205 ichac97R3StreamUnlock(pStreamCC);
1206
1207 LogFlowFuncLeaveRC(rc);
1208 return rc;
1209}
1210
1211
1212/**
1213 * Input streams: Pulls data from the mixer, putting it in the internal DMA
1214 * buffer.
1215 *
1216 * @param pStreamR3 The AC'97 stream (ring-3 bits).
1217 * @param pSink The mixer sink to pull from.
1218 */
1219static void ichac97R3StreamPullFromMixer(PAC97STREAMR3 pStreamR3, PAUDMIXSINK pSink)
1220{
1221# ifdef LOG_ENABLED
1222 uint64_t const offWriteOld = pStreamR3->State.offWrite;
1223# endif
1224 pStreamR3->State.offWrite = AudioMixerSinkTransferToCircBuf(pSink,
1225 pStreamR3->State.pCircBuf,
1226 pStreamR3->State.offWrite,
1227 pStreamR3->u8SD,
1228 pStreamR3->Dbg.Runtime.fEnabled
1229 ? pStreamR3->Dbg.Runtime.pFileStream : NULL);
1230
1231 Log3Func(("[SD%RU8] transferred=%#RX64 bytes -> @%#RX64\n", pStreamR3->u8SD,
1232 pStreamR3->State.offWrite - offWriteOld, pStreamR3->State.offWrite));
1233
1234 /* Update buffer stats. */
1235 pStreamR3->State.StatDmaBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
1236}
1237
1238
1239/**
1240 * Output streams: Pushes data to the mixer.
1241 *
1242 * @param pStreamR3 The AC'97 stream (ring-3 bits).
1243 * @param pSink The mixer sink to push to.
1244 */
1245static void ichac97R3StreamPushToMixer(PAC97STREAMR3 pStreamR3, PAUDMIXSINK pSink)
1246{
1247# ifdef LOG_ENABLED
1248 uint64_t const offReadOld = pStreamR3->State.offRead;
1249# endif
1250 pStreamR3->State.offRead = AudioMixerSinkTransferFromCircBuf(pSink,
1251 pStreamR3->State.pCircBuf,
1252 pStreamR3->State.offRead,
1253 pStreamR3->u8SD,
1254 pStreamR3->Dbg.Runtime.fEnabled
1255 ? pStreamR3->Dbg.Runtime.pFileStream : NULL);
1256
1257 Log3Func(("[SD%RU8] transferred=%#RX64 bytes -> @%#RX64\n", pStreamR3->u8SD,
1258 pStreamR3->State.offRead - offReadOld, pStreamR3->State.offRead));
1259
1260 /* Update buffer stats. */
1261 pStreamR3->State.StatDmaBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf);
1262}
1263
1264
1265/**
1266 * Updates an AC'97 stream by doing its DMA transfers.
1267 *
1268 * The host sink(s) set the overall pace (bird: no it doesn't, the DMA timer
1269 * does - we just hope like heck it matches the speed at which the *backend*
1270 * host audio driver processes samples).
1271 *
1272 * @param pDevIns The device instance.
1273 * @param pThis The shared AC'97 state.
1274 * @param pThisCC The ring-3 AC'97 state.
1275 * @param pStream The AC'97 stream to update (shared).
1276 * @param pStreamCC The AC'97 stream to update (ring-3).
1277 * @param pSink The sink being updated.
1278 */
1279static void ichac97R3StreamUpdateDma(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC,
1280 PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, PAUDMIXSINK pSink)
1281{
1282 RT_NOREF(pThisCC);
1283 int rc2;
1284
1285 /* The amount we're supposed to be transfering in this DMA period. */
1286 uint32_t cbPeriod = pStreamCC->State.cbTransferChunk;
1287
1288 /*
1289 * Output streams (SDO).
1290 */
1291 if (pStreamCC->State.Cfg.enmDir == PDMAUDIODIR_OUT)
1292 {
1293 /*
1294 * Check how much room we have in our DMA buffer. There should be at
1295 * least one period worth of space there or we're in an overflow situation.
1296 */
1297 uint32_t cbStreamFree = ichac97R3StreamGetFree(pStreamCC);
1298 if (cbStreamFree >= cbPeriod)
1299 { /* likely */ }
1300 else
1301 {
1302 STAM_REL_COUNTER_INC(&pStreamCC->State.StatDmaFlowProblems);
1303 Log(("ichac97R3StreamUpdateDma: Warning! Stream #%u has insufficient space free: %u bytes, need %u. Will try move data out of the buffer...\n",
1304 pStreamCC->u8SD, cbStreamFree, cbPeriod));
1305 int rc = AudioMixerSinkTryLock(pSink);
1306 if (RT_SUCCESS(rc))
1307 {
1308 ichac97R3StreamPushToMixer(pStreamCC, pSink);
1309 AudioMixerSinkUpdate(pSink, 0, 0);
1310 AudioMixerSinkUnlock(pSink);
1311 }
1312 else
1313 RTThreadYield();
1314 Log(("ichac97R3StreamUpdateDma: Gained %u bytes.\n", ichac97R3StreamGetFree(pStreamCC) - cbStreamFree));
1315
1316 cbStreamFree = ichac97R3StreamGetFree(pStreamCC);
1317 if (cbStreamFree < cbPeriod)
1318 {
1319 /* Unable to make sufficient space. Drop the whole buffer content.
1320 * This is needed in order to keep the device emulation running at a constant rate,
1321 * at the cost of losing valid (but too much) data. */
1322 STAM_REL_COUNTER_INC(&pStreamCC->State.StatDmaFlowErrors);
1323 LogRel2(("AC97: Warning: Hit stream #%RU8 overflow, dropping %u bytes of audio data\n",
1324 pStreamCC->u8SD, ichac97R3StreamGetUsed(pStreamCC)));
1325# ifdef AC97_STRICT
1326 AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamCC->u8SD));
1327# endif
1328 RTCircBufReset(pStreamCC->State.pCircBuf);
1329 pStreamCC->State.offWrite = 0;
1330 pStreamCC->State.offRead = 0;
1331 cbStreamFree = ichac97R3StreamGetFree(pStreamCC);
1332 Assert(cbStreamFree >= cbPeriod);
1333 }
1334 }
1335
1336 /*
1337 * Do the DMA transfer.
1338 */
1339 Log3Func(("[SD%RU8] PICB=%#x samples / %RU64 ms, cbFree=%#x / %RU64 ms, cbTransferChunk=%#x / %RU64 ms\n", pStream->u8SD,
1340 pStream->Regs.picb, PDMAudioPropsBytesToMilli(&pStreamCC->State.Cfg.Props,
1341 PDMAudioPropsSampleSize(&pStreamCC->State.Cfg.Props)
1342 * pStream->Regs.picb),
1343 cbStreamFree, PDMAudioPropsBytesToMilli(&pStreamCC->State.Cfg.Props, cbStreamFree),
1344 cbPeriod, PDMAudioPropsBytesToMilli(&pStreamCC->State.Cfg.Props, cbPeriod)));
1345
1346 rc2 = ichac97R3StreamTransfer(pDevIns, pThis, pStream, pStreamCC, RT_MIN(cbStreamFree, cbPeriod),
1347 false /*fWriteSilence*/, false /*fInput*/);
1348 AssertRC(rc2);
1349
1350 pStreamCC->State.tsLastUpdateNs = RTTimeNanoTS();
1351
1352
1353 /*
1354 * Notify the AIO thread.
1355 */
1356 rc2 = AudioMixerSinkSignalUpdateJob(pSink);
1357 AssertRC(rc2);
1358 }
1359 /*
1360 * Input stream (SDI).
1361 */
1362 else
1363 {
1364 /*
1365 * See how much data we've got buffered...
1366 */
1367 bool fWriteSilence = false;
1368 uint32_t cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC);
1369 if (pStreamCC->State.fInputPreBuffered && cbStreamUsed >= cbPeriod)
1370 { /*likely*/ }
1371 /*
1372 * Because it may take a while for the input stream to get going (at least
1373 * with pulseaudio), we feed the guest silence till we've pre-buffer a
1374 * couple of timer Hz periods. (This avoid lots of bogus buffer underruns
1375 * when starting an input stream and hogging the timer EMT.)
1376 */
1377 else if (!pStreamCC->State.fInputPreBuffered)
1378 {
1379 uint32_t const cbPreBuffer = PDMAudioPropsNanoToBytes(&pStreamCC->State.Cfg.Props,
1380 RT_NS_1SEC / pStreamCC->State.uTimerHz);
1381 if (cbStreamUsed < cbPreBuffer)
1382 {
1383 Log3(("hdaR3StreamUpdateDma: Pre-buffering (got %#x out of %#x bytes)...\n", cbStreamUsed, cbPreBuffer));
1384 fWriteSilence = true;
1385 cbStreamUsed = cbPeriod;
1386 }
1387 else
1388 {
1389 Log3(("hdaR3StreamUpdateDma: Completed pre-buffering (got %#x, needed %#x bytes).\n", cbStreamUsed, cbPreBuffer));
1390 pStreamCC->State.fInputPreBuffered = true;
1391 fWriteSilence = ichac97R3StreamGetFree(pStreamCC) >= cbPreBuffer + cbPreBuffer / 2;
1392 if (fWriteSilence)
1393 cbStreamUsed = cbPeriod;
1394 }
1395 }
1396 /*
1397 * When we're low on data, we must really try fetch some ourselves
1398 * as buffer underruns must not happen.
1399 */
1400 else
1401 {
1402 STAM_REL_COUNTER_INC(&pStreamCC->State.StatDmaFlowProblems);
1403 Log(("ichac97R3StreamUpdateDma: Warning! Stream #%u has insufficient data available: %u bytes, need %u. Will try move pull more data into the buffer...\n",
1404 pStreamCC->u8SD, cbStreamUsed, cbPeriod));
1405 int rc = AudioMixerSinkTryLock(pSink);
1406 if (RT_SUCCESS(rc))
1407 {
1408 AudioMixerSinkUpdate(pSink, cbStreamUsed, cbPeriod);
1409 ichac97R3StreamPullFromMixer(pStreamCC, pSink);
1410 AudioMixerSinkUnlock(pSink);
1411 }
1412 else
1413 RTThreadYield();
1414 Log(("ichac97R3StreamUpdateDma: Gained %u bytes.\n", ichac97R3StreamGetUsed(pStreamCC) - cbStreamUsed));
1415 cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC);
1416 if (cbStreamUsed < cbPeriod)
1417 {
1418 /* Unable to find sufficient input data by simple prodding.
1419 In order to keep a constant byte stream following thru the DMA
1420 engine into the guest, we will try again and then fall back on
1421 filling the gap with silence. */
1422 uint32_t cbSilence = 0;
1423 do
1424 {
1425 AudioMixerSinkLock(pSink);
1426
1427 cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC);
1428 if (cbStreamUsed < cbPeriod)
1429 {
1430 ichac97R3StreamPullFromMixer(pStreamCC, pSink);
1431 cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC);
1432 while (cbStreamUsed < cbPeriod)
1433 {
1434 void *pvDstBuf;
1435 size_t cbDstBuf;
1436 RTCircBufAcquireWriteBlock(pStreamCC->State.pCircBuf, cbPeriod - cbStreamUsed,
1437 &pvDstBuf, &cbDstBuf);
1438 RT_BZERO(pvDstBuf, cbDstBuf);
1439 RTCircBufReleaseWriteBlock(pStreamCC->State.pCircBuf, cbDstBuf);
1440 cbSilence += (uint32_t)cbDstBuf;
1441 cbStreamUsed += (uint32_t)cbDstBuf;
1442 }
1443 }
1444
1445 AudioMixerSinkUnlock(pSink);
1446 } while (cbStreamUsed < cbPeriod);
1447 if (cbSilence > 0)
1448 {
1449 STAM_REL_COUNTER_INC(&pStreamCC->State.StatDmaFlowErrors);
1450 STAM_REL_COUNTER_ADD(&pStreamCC->State.StatDmaFlowErrorBytes, cbSilence);
1451 LogRel2(("AC97: Warning: Stream #%RU8 underrun, added %u bytes of silence (%u us)\n", pStreamCC->u8SD,
1452 cbSilence, PDMAudioPropsBytesToMicro(&pStreamCC->State.Cfg.Props, cbSilence)));
1453 }
1454 }
1455 }
1456
1457 /*
1458 * Do the DMA'ing.
1459 */
1460 if (cbStreamUsed)
1461 {
1462 rc2 = ichac97R3StreamTransfer(pDevIns, pThis, pStream, pStreamCC, RT_MIN(cbPeriod, cbStreamUsed),
1463 fWriteSilence, true /*fInput*/);
1464 AssertRC(rc2);
1465
1466 pStreamCC->State.tsLastUpdateNs = RTTimeNanoTS();
1467 }
1468
1469 /*
1470 * We should always kick the AIO thread.
1471 */
1472 /** @todo This isn't entirely ideal. If we get into an underrun situation,
1473 * we ideally want the AIO thread to run right before the DMA timer
1474 * rather than right after it ran. */
1475 Log5Func(("Notifying AIO thread\n"));
1476 rc2 = AudioMixerSinkSignalUpdateJob(pSink);
1477 AssertRC(rc2);
1478 }
1479}
1480
1481
1482/**
1483 * @callback_method_impl{FNAUDMIXSINKUPDATE}
1484 *
1485 * For output streams this moves data from the internal DMA buffer (in which
1486 * ichac97R3StreamUpdateDma put it), thru the mixer and to the various backend
1487 * audio devices.
1488 *
1489 * For input streams this pulls data from the backend audio device(s), thru the
1490 * mixer and puts it in the internal DMA buffer ready for
1491 * ichac97R3StreamUpdateDma to pump into guest memory.
1492 */
1493static DECLCALLBACK(void) ichac97R3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser)
1494{
1495 PAC97STATER3 const pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
1496 PAC97STREAMR3 const pStreamCC = (PAC97STREAMR3)pvUser;
1497 Assert(pStreamCC->u8SD == (uintptr_t)(pStreamCC - &pThisCC->aStreams[0]));
1498 Assert(pSink == ichac97R3IndexToSink(pThisCC, pStreamCC->u8SD));
1499 RT_NOREF(pThisCC);
1500
1501 /*
1502 * Output (SDO).
1503 */
1504 if (pStreamCC->State.Cfg.enmDir == PDMAUDIODIR_OUT)
1505 ichac97R3StreamPushToMixer(pStreamCC, pSink);
1506 /*
1507 * Input (SDI).
1508 */
1509 else
1510 ichac97R3StreamPullFromMixer(pStreamCC, pSink);
1511}
1512
1513
1514/**
1515 * Updates the next transfer based on a specific amount of bytes.
1516 *
1517 * @param pDevIns The device instance.
1518 * @param pStream The AC'97 stream to update (shared).
1519 * @param pStreamCC The AC'97 stream to update (ring-3).
1520 */
1521static void ichac97R3StreamTransferUpdate(PPDMDEVINS pDevIns, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)
1522{
1523 /*
1524 * Get the number of bytes left in the current buffer.
1525 *
1526 * This isn't entirely optimal iff the current entry doesn't have IOC set, in
1527 * that case we should use the number of bytes to the next IOC. Unfortuantely,
1528 * it seems the spec doesn't allow us to prefetch more than one BDLE, so we
1529 * probably cannot look ahead without violating that restriction. This is
1530 * probably a purely theoretical problem at this point.
1531 */
1532 uint32_t const cbLeftInBdle = pStream->Regs.picb * PDMAudioPropsSampleSize(&pStreamCC->State.Cfg.Props);
1533 if (cbLeftInBdle > 0) /** @todo r=bird: see todo about this in ichac97R3StreamFetchBDLE. */
1534 {
1535 /*
1536 * Since the buffer can be up to 0xfffe samples long (frame aligning stereo
1537 * prevents 0xffff), which translates to 743ms at a 44.1kHz rate, we must
1538 * also take the nominal timer frequency into account here so we keep
1539 * moving data at a steady rate. (In theory, I think the guest can even
1540 * set up just one buffer and anticipate where we are in the buffer
1541 * processing when it writes/reads from it. Linux seems to be doing such
1542 * configs when not playing or something.)
1543 */
1544 uint32_t const cbMaxPerHz = PDMAudioPropsNanoToBytes(&pStreamCC->State.Cfg.Props, RT_NS_1SEC / pStreamCC->State.uTimerHz);
1545
1546 if (cbLeftInBdle <= cbMaxPerHz)
1547 pStreamCC->State.cbTransferChunk = cbLeftInBdle;
1548 /* Try avoid leaving a very short period at the end of a buffer. */
1549 else if (cbLeftInBdle >= cbMaxPerHz + cbMaxPerHz / 2)
1550 pStreamCC->State.cbTransferChunk = cbMaxPerHz;
1551 else
1552 pStreamCC->State.cbTransferChunk = PDMAudioPropsFloorBytesToFrame(&pStreamCC->State.Cfg.Props, cbLeftInBdle / 2);
1553
1554 /*
1555 * Translate the chunk size to timer ticks.
1556 */
1557 uint64_t const cNsXferChunk = PDMAudioPropsBytesToNano(&pStreamCC->State.Cfg.Props, pStreamCC->State.cbTransferChunk);
1558 pStreamCC->State.cTransferTicks = PDMDevHlpTimerFromNano(pDevIns, pStream->hTimer, cNsXferChunk);
1559 Assert(pStreamCC->State.cTransferTicks > 0);
1560
1561 Log3Func(("[SD%RU8] cbLeftInBdle=%#RX32 cbMaxPerHz=%#RX32 (%RU16Hz) -> cbTransferChunk=%#RX32 cTransferTicks=%RX64\n",
1562 pStream->u8SD, cbLeftInBdle, cbMaxPerHz, pStreamCC->State.uTimerHz,
1563 pStreamCC->State.cbTransferChunk, pStreamCC->State.cTransferTicks));
1564 }
1565}
1566
1567
1568/**
1569 * Sets the virtual device timer to a new expiration time.
1570 *
1571 * @param pDevIns The device instance.
1572 * @param pStream AC'97 stream to set timer for.
1573 * @param cTicksToDeadline The number of ticks to the new deadline.
1574 *
1575 * @remarks This used to be more complicated a long time ago...
1576 */
1577DECLINLINE(void) ichac97R3TimerSet(PPDMDEVINS pDevIns, PAC97STREAM pStream, uint64_t cTicksToDeadline)
1578{
1579 int rc = PDMDevHlpTimerSetRelative(pDevIns, pStream->hTimer, cTicksToDeadline, NULL /*pu64Now*/);
1580 AssertRC(rc);
1581}
1582
1583
1584/**
1585 * @callback_method_impl{FNTMTIMERDEV,
1586 * Timer callback which handles the audio data transfers on a periodic basis.}
1587 */
1588static DECLCALLBACK(void) ichac97R3Timer(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)
1589{
1590 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
1591 STAM_PROFILE_START(&pThis->StatTimer, a);
1592 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
1593 PAC97STREAM pStream = (PAC97STREAM)pvUser;
1594 PAC97STREAMR3 pStreamCC = &RT_SAFE_SUBSCRIPT8(pThisCC->aStreams, pStream->u8SD);
1595 Assert(hTimer == pStream->hTimer); RT_NOREF(hTimer);
1596
1597 Assert(pStream - &pThis->aStreams[0] == pStream->u8SD);
1598 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
1599 Assert(PDMDevHlpTimerIsLockOwner(pDevIns, pStream->hTimer));
1600
1601 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD);
1602 if (pSink && AudioMixerSinkIsActive(pSink))
1603 {
1604 ichac97R3StreamUpdateDma(pDevIns, pThis, pThisCC, pStream, pStreamCC, pSink);
1605
1606 ichac97R3StreamTransferUpdate(pDevIns, pStream, pStreamCC);
1607 ichac97R3TimerSet(pDevIns, pStream, pStreamCC->State.cTransferTicks);
1608 }
1609
1610 STAM_PROFILE_STOP(&pThis->StatTimer, a);
1611}
1612
1613#endif /* IN_RING3 */
1614
1615
1616/*********************************************************************************************************************************
1617* AC'97 Stream Management *
1618*********************************************************************************************************************************/
1619#ifdef IN_RING3
1620
1621/**
1622 * Locks an AC'97 stream for serialized access.
1623 *
1624 * @returns VBox status code.
1625 * @param pStreamCC The AC'97 stream to lock (ring-3).
1626 */
1627DECLINLINE(void) ichac97R3StreamLock(PAC97STREAMR3 pStreamCC)
1628{
1629 int rc2 = RTCritSectEnter(&pStreamCC->State.CritSect);
1630 AssertRC(rc2);
1631}
1632
1633/**
1634 * Unlocks a formerly locked AC'97 stream.
1635 *
1636 * @returns VBox status code.
1637 * @param pStreamCC The AC'97 stream to unlock (ring-3).
1638 */
1639DECLINLINE(void) ichac97R3StreamUnlock(PAC97STREAMR3 pStreamCC)
1640{
1641 int rc2 = RTCritSectLeave(&pStreamCC->State.CritSect);
1642 AssertRC(rc2);
1643}
1644
1645#endif /* IN_RING3 */
1646
1647/**
1648 * Updates the status register (SR) of an AC'97 audio stream.
1649 *
1650 * @param pDevIns The device instance.
1651 * @param pThis The shared AC'97 state.
1652 * @param pStream AC'97 stream to update SR for.
1653 * @param new_sr New value for status register (SR).
1654 */
1655static void ichac97StreamUpdateSR(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, uint32_t new_sr)
1656{
1657 PAC97BMREGS pRegs = &pStream->Regs;
1658
1659 bool fSignal = false;
1660 int iIRQL = 0;
1661
1662 uint32_t new_mask = new_sr & AC97_SR_INT_MASK;
1663 uint32_t old_mask = pRegs->sr & AC97_SR_INT_MASK;
1664
1665 if (new_mask ^ old_mask)
1666 {
1667 /** @todo Is IRQ deasserted when only one of status bits is cleared? */
1668 if (!new_mask)
1669 {
1670 fSignal = true;
1671 iIRQL = 0;
1672 }
1673 else if ((new_mask & AC97_SR_LVBCI) && (pRegs->cr & AC97_CR_LVBIE))
1674 {
1675 fSignal = true;
1676 iIRQL = 1;
1677 }
1678 else if ((new_mask & AC97_SR_BCIS) && (pRegs->cr & AC97_CR_IOCE))
1679 {
1680 fSignal = true;
1681 iIRQL = 1;
1682 }
1683 }
1684
1685 pRegs->sr = new_sr;
1686
1687 LogFlowFunc(("IOC%d, LVB%d, sr=%#x, fSignal=%RTbool, IRQL=%d\n",
1688 pRegs->sr & AC97_SR_BCIS, pRegs->sr & AC97_SR_LVBCI, pRegs->sr, fSignal, iIRQL));
1689
1690 if (fSignal)
1691 {
1692 static uint32_t const s_aMasks[] = { AC97_GS_PIINT, AC97_GS_POINT, AC97_GS_MINT };
1693 Assert(pStream->u8SD < AC97_MAX_STREAMS);
1694 if (iIRQL)
1695 pThis->glob_sta |= s_aMasks[pStream->u8SD];
1696 else
1697 pThis->glob_sta &= ~s_aMasks[pStream->u8SD];
1698
1699 LogFlowFunc(("Setting IRQ level=%d\n", iIRQL));
1700 PDMDevHlpPCISetIrq(pDevIns, 0, iIRQL);
1701 }
1702}
1703
1704/**
1705 * Writes a new value to a stream's status register (SR).
1706 *
1707 * @param pDevIns The device instance.
1708 * @param pThis The shared AC'97 device state.
1709 * @param pStream Stream to update SR for.
1710 * @param u32Val New value to set the stream's SR to.
1711 */
1712static void ichac97StreamWriteSR(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, uint32_t u32Val)
1713{
1714 PAC97BMREGS pRegs = &pStream->Regs;
1715
1716 Log3Func(("[SD%RU8] SR <- %#x (sr %#x)\n", pStream->u8SD, u32Val, pRegs->sr));
1717
1718 pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK);
1719 ichac97StreamUpdateSR(pDevIns, pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK));
1720}
1721
1722#ifdef IN_RING3
1723
1724/**
1725 * Resets an AC'97 stream.
1726 *
1727 * @param pThis The shared AC'97 state.
1728 * @param pStream The AC'97 stream to reset (shared).
1729 * @param pStreamCC The AC'97 stream to reset (ring-3).
1730 */
1731static void ichac97R3StreamReset(PAC97STATE pThis, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)
1732{
1733 ichac97R3StreamLock(pStreamCC);
1734
1735 LogFunc(("[SD%RU8]\n", pStream->u8SD));
1736
1737 if (pStreamCC->State.pCircBuf)
1738 RTCircBufReset(pStreamCC->State.pCircBuf);
1739
1740 PAC97BMREGS pRegs = &pStream->Regs;
1741
1742 pRegs->bdbar = 0;
1743 pRegs->civ = 0;
1744 pRegs->lvi = 0;
1745
1746 pRegs->picb = 0;
1747 pRegs->piv = 0; /* Note! Because this is also zero, we will actually start transferring with BDLE00. */
1748 pRegs->cr = pRegs->cr & AC97_CR_DONT_CLEAR_MASK;
1749 pRegs->bd_valid = 0;
1750
1751 RT_ZERO(pThis->silence);
1752
1753 ichac97R3StreamUnlock(pStreamCC);
1754}
1755
1756/**
1757 * Retrieves a specific driver stream of a AC'97 driver.
1758 *
1759 * @returns Pointer to driver stream if found, or NULL if not found.
1760 * @param pDrv Driver to retrieve driver stream for.
1761 * @param enmDir Stream direction to retrieve.
1762 * @param enmPath Stream destination / source to retrieve.
1763 */
1764static PAC97DRIVERSTREAM ichac97R3MixerGetDrvStream(PAC97DRIVER pDrv, PDMAUDIODIR enmDir, PDMAUDIOPATH enmPath)
1765{
1766 if (enmDir == PDMAUDIODIR_IN)
1767 {
1768 LogFunc(("enmRecSource=%d\n", enmPath));
1769 switch (enmPath)
1770 {
1771 case PDMAUDIOPATH_IN_LINE:
1772 return &pDrv->LineIn;
1773 case PDMAUDIOPATH_IN_MIC:
1774 return &pDrv->MicIn;
1775 default:
1776 AssertFailedBreak();
1777 }
1778 }
1779 else if (enmDir == PDMAUDIODIR_OUT)
1780 {
1781 LogFunc(("enmPlaybackDst=%d\n", enmPath));
1782 switch (enmPath)
1783 {
1784 case PDMAUDIOPATH_OUT_FRONT:
1785 return &pDrv->Out;
1786 default:
1787 AssertFailedBreak();
1788 }
1789 }
1790 else
1791 AssertFailed();
1792
1793 return NULL;
1794}
1795
1796/**
1797 * Adds a driver stream to a specific mixer sink.
1798 *
1799 * Called by ichac97R3MixerAddDrvStreams() and ichac97R3MixerAddDrv().
1800 *
1801 * @returns VBox status code.
1802 * @param pDevIns The device instance.
1803 * @param pMixSink Mixer sink to add driver stream to.
1804 * @param pCfg Stream configuration to use.
1805 * @param pDrv Driver stream to add.
1806 */
1807static int ichac97R3MixerAddDrvStream(PPDMDEVINS pDevIns, PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg, PAC97DRIVER pDrv)
1808{
1809 AssertPtrReturn(pMixSink, VERR_INVALID_POINTER);
1810
1811 PPDMAUDIOSTREAMCFG pStreamCfg = PDMAudioStrmCfgDup(pCfg); /** @todo r=bird: This seems kind of pointless... */
1812 if (!pStreamCfg)
1813 return VERR_NO_MEMORY;
1814
1815 AssertCompile(sizeof(pStreamCfg->szName) == sizeof(pCfg->szName));
1816 RTStrCopy(pStreamCfg->szName, sizeof(pStreamCfg->szName), pCfg->szName);
1817
1818 LogFunc(("[LUN#%RU8] %s\n", pDrv->uLUN, pStreamCfg->szName));
1819
1820 int rc;
1821
1822 PAC97DRIVERSTREAM pDrvStream = ichac97R3MixerGetDrvStream(pDrv, pStreamCfg->enmDir, pStreamCfg->enmPath);
1823 if (pDrvStream)
1824 {
1825 AssertMsg(pDrvStream->pMixStrm == NULL, ("[LUN#%RU8] Driver stream already present when it must not\n", pDrv->uLUN));
1826
1827 PAUDMIXSTREAM pMixStrm;
1828 rc = AudioMixerSinkCreateStream(pMixSink, pDrv->pConnector, pStreamCfg, pDevIns, &pMixStrm);
1829 LogFlowFunc(("LUN#%RU8: Created stream \"%s\" for sink, rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName, rc));
1830 if (RT_SUCCESS(rc))
1831 {
1832 rc = AudioMixerSinkAddStream(pMixSink, pMixStrm);
1833 LogFlowFunc(("LUN#%RU8: Added stream \"%s\" to sink, rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName, rc));
1834 if (RT_SUCCESS(rc))
1835 pDrvStream->pMixStrm = pMixStrm;
1836 else
1837 AudioMixerStreamDestroy(pMixStrm, pDevIns, true /*fImmediate*/);
1838 }
1839 }
1840 else
1841 rc = VERR_INVALID_PARAMETER;
1842
1843 PDMAudioStrmCfgFree(pStreamCfg);
1844
1845 LogFlowFuncLeaveRC(rc);
1846 return rc;
1847}
1848
1849
1850/**
1851 * Adds all current driver streams to a specific mixer sink.
1852 *
1853 * Called by ichac97R3StreamSetUp().
1854 *
1855 * @returns VBox status code.
1856 * @param pDevIns The device instance.
1857 * @param pThisCC The ring-3 AC'97 state.
1858 * @param pMixSink Mixer sink to add stream to.
1859 * @param pCfg Stream configuration to use.
1860 */
1861static int ichac97R3MixerAddDrvStreams(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg)
1862{
1863 AssertPtrReturn(pMixSink, VERR_INVALID_POINTER);
1864
1865 int rc;
1866 if (AudioHlpStreamCfgIsValid(pCfg))
1867 {
1868 rc = AudioMixerSinkSetFormat(pMixSink, &pCfg->Props);
1869 if (RT_SUCCESS(rc))
1870 {
1871 PAC97DRIVER pDrv;
1872 RTListForEach(&pThisCC->lstDrv, pDrv, AC97DRIVER, Node)
1873 {
1874 int rc2 = ichac97R3MixerAddDrvStream(pDevIns, pMixSink, pCfg, pDrv);
1875 if (RT_FAILURE(rc2))
1876 LogFunc(("Attaching stream failed with %Rrc\n", rc2));
1877
1878 /* Do not pass failure to rc here, as there might be drivers which aren't
1879 configured / ready yet. */
1880 }
1881 }
1882 }
1883 else
1884 rc = VERR_INVALID_PARAMETER;
1885
1886 LogFlowFuncLeaveRC(rc);
1887 return rc;
1888}
1889
1890
1891/**
1892 * Removes a driver stream from a specific mixer sink.
1893 *
1894 * Worker for ichac97R3MixerRemoveDrvStreams.
1895 *
1896 * @param pDevIns The device instance.
1897 * @param pMixSink Mixer sink to remove audio streams from.
1898 * @param enmDir Stream direction to remove.
1899 * @param enmPath Stream destination / source to remove.
1900 * @param pDrv Driver stream to remove.
1901 */
1902static void ichac97R3MixerRemoveDrvStream(PPDMDEVINS pDevIns, PAUDMIXSINK pMixSink, PDMAUDIODIR enmDir,
1903 PDMAUDIOPATH enmPath, PAC97DRIVER pDrv)
1904{
1905 PAC97DRIVERSTREAM pDrvStream = ichac97R3MixerGetDrvStream(pDrv, enmDir, enmPath);
1906 if (pDrvStream)
1907 {
1908 if (pDrvStream->pMixStrm)
1909 {
1910 AudioMixerSinkRemoveStream(pMixSink, pDrvStream->pMixStrm);
1911
1912 AudioMixerStreamDestroy(pDrvStream->pMixStrm, pDevIns, false /*fImmediate*/);
1913 pDrvStream->pMixStrm = NULL;
1914 }
1915 }
1916}
1917
1918/**
1919 * Removes all driver streams from a specific mixer sink.
1920 *
1921 * Called by ichac97R3StreamSetUp() and ichac97R3StreamsDestroy().
1922 *
1923 * @param pDevIns The device instance.
1924 * @param pThisCC The ring-3 AC'97 state.
1925 * @param pMixSink Mixer sink to remove audio streams from.
1926 * @param enmDir Stream direction to remove.
1927 * @param enmPath Stream destination / source to remove.
1928 */
1929static void ichac97R3MixerRemoveDrvStreams(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, PAUDMIXSINK pMixSink,
1930 PDMAUDIODIR enmDir, PDMAUDIOPATH enmPath)
1931{
1932 AssertPtrReturnVoid(pMixSink);
1933
1934 PAC97DRIVER pDrv;
1935 RTListForEach(&pThisCC->lstDrv, pDrv, AC97DRIVER, Node)
1936 {
1937 ichac97R3MixerRemoveDrvStream(pDevIns, pMixSink, enmDir, enmPath, pDrv);
1938 }
1939}
1940
1941
1942/**
1943 * Gets the frequency of a given stream.
1944 *
1945 * @returns The frequency. Zero if invalid stream index.
1946 * @param pThis The shared AC'97 device state.
1947 * @param idxStream The stream.
1948 */
1949DECLINLINE(uint32_t) ichach97R3CalcStreamHz(PAC97STATE pThis, uint8_t idxStream)
1950{
1951 switch (idxStream)
1952 {
1953 case AC97SOUNDSOURCE_PI_INDEX:
1954 return ichac97MixerGet(pThis, AC97_PCM_LR_ADC_Rate);
1955
1956 case AC97SOUNDSOURCE_MC_INDEX:
1957 return ichac97MixerGet(pThis, AC97_MIC_ADC_Rate);
1958
1959 case AC97SOUNDSOURCE_PO_INDEX:
1960 return ichac97MixerGet(pThis, AC97_PCM_Front_DAC_Rate);
1961
1962 default:
1963 AssertMsgFailedReturn(("%d\n", idxStream), 0);
1964 }
1965}
1966
1967
1968/**
1969 * Gets the PCM properties for a given stream.
1970 *
1971 * @returns pProps.
1972 * @param pThis The shared AC'97 device state.
1973 * @param idxStream Which stream
1974 * @param pProps Where to return the stream properties.
1975 */
1976DECLINLINE(PPDMAUDIOPCMPROPS) ichach97R3CalcStreamProps(PAC97STATE pThis, uint8_t idxStream, PPDMAUDIOPCMPROPS pProps)
1977{
1978 PDMAudioPropsInit(pProps, 2 /*16-bit*/, true /*signed*/, 2 /*stereo*/, ichach97R3CalcStreamHz(pThis, idxStream));
1979 return pProps;
1980}
1981
1982
1983/**
1984 * Sets up an AC'97 stream with its current mixer settings.
1985 *
1986 * This will set up an AC'97 stream with 2 (stereo) channels, 16-bit samples and
1987 * the last set sample rate in the AC'97 mixer for this stream.
1988 *
1989 * @returns VBox status code.
1990 * @param pDevIns The device instance.
1991 * @param pThis The shared AC'97 device state (shared).
1992 * @param pThisCC The shared AC'97 device state (ring-3).
1993 * @param pStream The AC'97 stream to open (shared).
1994 * @param pStreamCC The AC'97 stream to open (ring-3).
1995 * @param fForce Whether to force re-opening the stream or not.
1996 * Otherwise re-opening only will happen if the PCM properties have changed.
1997 */
1998static int ichac97R3StreamSetUp(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC, PAC97STREAM pStream,
1999 PAC97STREAMR3 pStreamCC, bool fForce)
2000{
2001 /*
2002 * Assemble the stream config and get the associated mixer sink.
2003 */
2004 PDMAUDIOPCMPROPS PropsTmp;
2005 PDMAUDIOSTREAMCFG Cfg;
2006 PDMAudioStrmCfgInitWithProps(&Cfg, ichach97R3CalcStreamProps(pThis, pStream->u8SD, &PropsTmp));
2007 Assert(Cfg.enmDir != PDMAUDIODIR_UNKNOWN);
2008
2009 PAUDMIXSINK pMixSink;
2010 switch (pStream->u8SD)
2011 {
2012 case AC97SOUNDSOURCE_PI_INDEX:
2013 Cfg.enmDir = PDMAUDIODIR_IN;
2014 Cfg.enmPath = PDMAUDIOPATH_IN_LINE;
2015 RTStrCopy(Cfg.szName, sizeof(Cfg.szName), "Line-In");
2016
2017 pMixSink = pThisCC->pSinkLineIn;
2018 break;
2019
2020 case AC97SOUNDSOURCE_MC_INDEX:
2021 Cfg.enmDir = PDMAUDIODIR_IN;
2022 Cfg.enmPath = PDMAUDIOPATH_IN_MIC;
2023 RTStrCopy(Cfg.szName, sizeof(Cfg.szName), "Mic-In");
2024
2025 pMixSink = pThisCC->pSinkMicIn;
2026 break;
2027
2028 case AC97SOUNDSOURCE_PO_INDEX:
2029 Cfg.enmDir = PDMAUDIODIR_OUT;
2030 Cfg.enmPath = PDMAUDIOPATH_OUT_FRONT;
2031 RTStrCopy(Cfg.szName, sizeof(Cfg.szName), "Output");
2032
2033 pMixSink = pThisCC->pSinkOut;
2034 break;
2035
2036 default:
2037 AssertMsgFailedReturn(("u8SD=%d\n", pStream->u8SD), VERR_INTERNAL_ERROR_3);
2038 }
2039
2040 /*
2041 * Don't continue if the frequency is out of range (the rest of the
2042 * properties should be okay).
2043 */
2044 char szTmp[PDMAUDIOSTRMCFGTOSTRING_MAX];
2045 ASSERT_GUEST_MSG_RETURN(AudioHlpStreamCfgIsValid(&Cfg),
2046 ("Invalid stream #%u rate: %s\n", pStreamCC->u8SD,
2047 PDMAudioStrmCfgToString(&Cfg, szTmp, sizeof(szTmp)) ),
2048 VERR_OUT_OF_RANGE);
2049
2050 /*
2051 * Read the buffer descriptors and check what the max distance between
2052 * interrupts are, so we can more correctly size the internal DMA buffer.
2053 *
2054 * Note! The buffer list are not fixed once the stream starts running as
2055 * with HDA, so this is just a general idea of what the guest is
2056 * up to and we cannot really make much of a plan out of it.
2057 */
2058 AC97BDLE aBdl[AC97_MAX_BDLE];
2059 RT_ZERO(aBdl);
2060 PDMDevHlpPCIPhysRead(pDevIns, pStream->Regs.bdbar, aBdl, sizeof(aBdl));
2061
2062 uint8_t const bLvi = pStream->Regs.lvi % AC97_MAX_BDLE /* paranoia */;
2063 uint8_t const bCiv = pStream->Regs.civ % AC97_MAX_BDLE /* paranoia */;
2064 uint32_t cSamplesMax = 0;
2065 uint32_t cSamplesMin = UINT32_MAX;
2066 uint32_t cSamplesCur = 0;
2067 uint32_t cSamplesTotal = 0;
2068 uint32_t cBuffers = 1;
2069 for (uintptr_t i = bCiv; ; cBuffers++)
2070 {
2071 cSamplesTotal += aBdl[i].ctl_len & AC97_BD_LEN_MASK;
2072 cSamplesCur += aBdl[i].ctl_len & AC97_BD_LEN_MASK;
2073 if (aBdl[i].ctl_len & AC97_BD_IOC)
2074 {
2075 if (cSamplesCur > cSamplesMax)
2076 cSamplesMax = cSamplesCur;
2077 if (cSamplesCur < cSamplesMin)
2078 cSamplesMin = cSamplesCur;
2079 cSamplesCur = 0;
2080 }
2081
2082 /* Advance. */
2083 if (i != bLvi)
2084 i = (i + 1) % RT_ELEMENTS(aBdl);
2085 else
2086 break;
2087 }
2088 if (!cSamplesCur)
2089 { /* likely */ }
2090 else if (!cSamplesMax)
2091 {
2092 LogFlowFunc(("%u buffers without IOC set, assuming %#x samples as the IOC period.\n", cBuffers, cSamplesMax));
2093 cSamplesMin = cSamplesMax = cSamplesCur;
2094 }
2095 else if (cSamplesCur > cSamplesMax)
2096 {
2097 LogFlowFunc(("final buffer is without IOC, using open period as max (%#x vs current max %#x).\n", cSamplesCur, cSamplesMax));
2098 cSamplesMax = cSamplesCur;
2099 }
2100 else
2101 LogFlowFunc(("final buffer is without IOC, ignoring (%#x vs current max %#x).\n", cSamplesCur, cSamplesMax));
2102
2103 uint32_t const cbDmaMinBuf = cSamplesMax * PDMAudioPropsSampleSize(&Cfg.Props) * 3; /* see further down */
2104 uint32_t const cMsDmaMinBuf = PDMAudioPropsBytesToMilli(&Cfg.Props, cbDmaMinBuf);
2105 LogRel3(("AC97: [SD%RU8] buffer length stats: total=%#x in %u buffers, min=%#x, max=%#x => min DMA buffer %u ms / %#x bytes\n",
2106 pStream->u8SD, cSamplesTotal, cBuffers, cSamplesMin, cSamplesMax, cMsDmaMinBuf, cbDmaMinBuf));
2107
2108 /*
2109 * Calculate the timer Hz / scheduling hint based on the stream frame rate.
2110 */
2111 uint32_t uTimerHz;
2112 if (pThis->uTimerHz == AC97_TIMER_HZ_DEFAULT) /* Make sure that we don't have any custom Hz rate set we want to enforce */
2113 {
2114 if (Cfg.Props.uHz > 44100) /* E.g. 48000 Hz. */
2115 uTimerHz = 200;
2116 else
2117 uTimerHz = AC97_TIMER_HZ_DEFAULT;
2118 }
2119 else
2120 uTimerHz = pThis->uTimerHz;
2121
2122 if ( uTimerHz >= 10
2123 && uTimerHz <= 500)
2124 { /* likely */ }
2125 else
2126 {
2127 LogFunc(("[SD%RU8] Adjusting uTimerHz=%u to %u\n", pStream->u8SD, uTimerHz,
2128 Cfg.Props.uHz > 44100 ? 200 : AC97_TIMER_HZ_DEFAULT));
2129 uTimerHz = Cfg.Props.uHz > 44100 ? 200 : AC97_TIMER_HZ_DEFAULT;
2130 }
2131
2132 /* Translate it to a scheduling hint. */
2133 uint32_t const cMsSchedulingHint = RT_MS_1SEC / uTimerHz;
2134
2135 /*
2136 * Calculate the circular buffer size so we can decide whether to recreate
2137 * the stream or not.
2138 *
2139 * As mentioned in the HDA code, this should be at least able to hold the
2140 * data transferred in three DMA periods and in three AIO period (whichever
2141 * is higher). However, if we assume that the DMA code will engage the DMA
2142 * timer thread (currently EMT) if the AIO thread isn't getting schduled to
2143 * transfer data thru the stack, we don't need to go overboard and double
2144 * the minimums here. The less buffer the less possible delay can build when
2145 * TM is doing catch up.
2146 */
2147 uint32_t cMsCircBuf = Cfg.enmDir == PDMAUDIODIR_IN ? pThis->cMsCircBufIn : pThis->cMsCircBufOut;
2148 cMsCircBuf = RT_MAX(cMsCircBuf, cMsDmaMinBuf);
2149 cMsCircBuf = RT_MAX(cMsCircBuf, cMsSchedulingHint * 3);
2150 cMsCircBuf = RT_MIN(cMsCircBuf, RT_MS_1SEC * 2);
2151 uint32_t const cbCircBuf = PDMAudioPropsMilliToBytes(&Cfg.Props, cMsCircBuf);
2152
2153 LogFlowFunc(("Stream %u: uTimerHz: %u -> %u; cMsSchedulingHint: %u -> %u; cbCircBuf: %#zx -> %#x (%u ms, cMsDmaMinBuf=%u)%s\n",
2154 pStreamCC->State.uTimerHz, uTimerHz, pStreamCC->State.Cfg.Device.cMsSchedulingHint, cMsSchedulingHint,
2155 pStreamCC->State.pCircBuf ? RTCircBufSize(pStreamCC->State.pCircBuf) : 0, cbCircBuf, cMsCircBuf, cMsDmaMinBuf,
2156 !pStreamCC->State.pCircBuf || RTCircBufSize(pStreamCC->State.pCircBuf) != cbCircBuf ? " - re-creating DMA buffer" : ""));
2157
2158 /*
2159 * Update the stream's timer rate and scheduling hint, re-registering the AIO
2160 * update job if necessary.
2161 */
2162 if ( pStreamCC->State.Cfg.Device.cMsSchedulingHint != cMsSchedulingHint
2163 || !pStreamCC->State.fRegisteredAsyncUpdateJob)
2164 {
2165 if (pStreamCC->State.fRegisteredAsyncUpdateJob)
2166 AudioMixerSinkRemoveUpdateJob(pMixSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC);
2167 int rc2 = AudioMixerSinkAddUpdateJob(pMixSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC,
2168 pStreamCC->State.Cfg.Device.cMsSchedulingHint);
2169 AssertRC(rc2);
2170 pStreamCC->State.fRegisteredAsyncUpdateJob = RT_SUCCESS(rc2) || rc2 == VERR_ALREADY_EXISTS;
2171 }
2172
2173 pStreamCC->State.uTimerHz = uTimerHz;
2174 Cfg.Device.cMsSchedulingHint = cMsSchedulingHint;
2175
2176 /*
2177 * Re-create the circular buffer if necessary, resetting if not.
2178 */
2179 if ( pStreamCC->State.pCircBuf
2180 && RTCircBufSize(pStreamCC->State.pCircBuf) == cbCircBuf)
2181 RTCircBufReset(pStreamCC->State.pCircBuf);
2182 else
2183 {
2184 if (pStreamCC->State.pCircBuf)
2185 RTCircBufDestroy(pStreamCC->State.pCircBuf);
2186
2187 int rc = RTCircBufCreate(&pStreamCC->State.pCircBuf, cbCircBuf);
2188 AssertRCReturnStmt(rc, pStreamCC->State.pCircBuf = NULL, rc);
2189
2190 pStreamCC->State.StatDmaBufSize = (uint32_t)RTCircBufSize(pStreamCC->State.pCircBuf);
2191 }
2192 Assert(pStreamCC->State.StatDmaBufSize == cbCircBuf);
2193
2194 /*
2195 * Only (re-)create the stream (and driver chain) if we really have to.
2196 * Otherwise avoid this and just reuse it, as this costs performance.
2197 */
2198 int rc = VINF_SUCCESS;
2199 if ( fForce
2200 || !PDMAudioStrmCfgMatchesProps(&Cfg, &pStreamCC->State.Cfg.Props)
2201 || (pStreamCC->State.nsRetrySetup && RTTimeNanoTS() >= pStreamCC->State.nsRetrySetup))
2202 {
2203 LogRel2(("AC97: Setting up stream #%u: %s\n", pStreamCC->u8SD, PDMAudioStrmCfgToString(&Cfg, szTmp, sizeof(szTmp)) ));
2204
2205 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pMixSink, Cfg.enmDir, Cfg.enmPath);
2206
2207 rc = ichac97R3MixerAddDrvStreams(pDevIns, pThisCC, pMixSink, &Cfg);
2208 if (RT_SUCCESS(rc))
2209 {
2210 PDMAudioStrmCfgCopy(&pStreamCC->State.Cfg, &Cfg);
2211 pStreamCC->State.nsRetrySetup = 0;
2212 LogFlowFunc(("[SD%RU8] success (uHz=%u)\n", pStreamCC->u8SD, rc, PDMAudioPropsHz(&Cfg.Props)));
2213 }
2214 else
2215 {
2216 LogFunc(("[SD%RU8] ichac97R3MixerAddDrvStreams failed: %Rrc (uHz=%u)\n",
2217 pStreamCC->u8SD, rc, PDMAudioPropsHz(&Cfg.Props)));
2218 pStreamCC->State.nsRetrySetup = RTTimeNanoTS() + 5*RT_NS_1SEC; /* retry in 5 seconds, unless config changes. */
2219 }
2220 }
2221 else
2222 LogFlowFunc(("[SD%RU8] Skipping set-up (unchanged: %s)\n",
2223 pStreamCC->u8SD, PDMAudioStrmCfgToString(&Cfg, szTmp, sizeof(szTmp))));
2224 return rc;
2225}
2226
2227
2228/**
2229 * Tears down an AC'97 stream (counter part to ichac97R3StreamSetUp).
2230 *
2231 * Empty stub at present, nothing to do here as we reuse streams and only really
2232 * re-open them if parameters changed (seldom).
2233 *
2234 * @param pStream The AC'97 stream to close (shared).
2235 */
2236static void ichac97R3StreamTearDown(PAC97STREAM pStream)
2237{
2238 RT_NOREF(pStream);
2239 LogFlowFunc(("[SD%RU8]\n", pStream->u8SD));
2240}
2241
2242
2243/**
2244 * Tears down and sets up an AC'97 stream on the backend side with the current
2245 * AC'97 mixer settings for this stream.
2246 *
2247 * @returns VBox status code.
2248 * @param pDevIns The device instance.
2249 * @param pThis The shared AC'97 device state.
2250 * @param pThisCC The ring-3 AC'97 device state.
2251 * @param pStream The AC'97 stream to re-open (shared).
2252 * @param pStreamCC The AC'97 stream to re-open (ring-3).
2253 * @param fForce Whether to force re-opening the stream or not.
2254 * Otherwise re-opening only will happen if the PCM properties have changed.
2255 */
2256static int ichac97R3StreamReSetUp(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC,
2257 PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, bool fForce)
2258{
2259 LogFlowFunc(("[SD%RU8]\n", pStream->u8SD));
2260 Assert(pStream->u8SD == pStreamCC->u8SD);
2261 Assert(pStream - &pThis->aStreams[0] == pStream->u8SD);
2262 Assert(pStreamCC - &pThisCC->aStreams[0] == pStream->u8SD);
2263
2264 ichac97R3StreamTearDown(pStream);
2265 return ichac97R3StreamSetUp(pDevIns, pThis, pThisCC, pStream, pStreamCC, fForce);
2266}
2267
2268
2269/**
2270 * Enables or disables an AC'97 audio stream.
2271 *
2272 * @returns VBox status code.
2273 * @param pDevIns The device instance.
2274 * @param pThis The shared AC'97 state.
2275 * @param pThisCC The ring-3 AC'97 state.
2276 * @param pStream The AC'97 stream to enable or disable (shared state).
2277 * @param pStreamCC The ring-3 stream state (matching to @a pStream).
2278 * @param fEnable Whether to enable or disable the stream.
2279 *
2280 */
2281static int ichac97R3StreamEnable(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC,
2282 PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, bool fEnable)
2283{
2284 ichac97R3StreamLock(pStreamCC);
2285 PAUDMIXSINK const pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD);
2286 AudioMixerSinkLock(pSink);
2287
2288 int rc = VINF_SUCCESS;
2289 /*
2290 * Enable.
2291 */
2292 if (fEnable)
2293 {
2294 /* Reset the input pre-buffering state. */
2295 pStreamCC->State.fInputPreBuffered = false;
2296
2297 /* Set up (update) the AC'97 stream as needed. */
2298 rc = ichac97R3StreamSetUp(pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fForce */);
2299 if (RT_SUCCESS(rc))
2300 {
2301 /* Open debug files. */
2302 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))
2303 { /* likely */ }
2304 else
2305 {
2306 if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileStream))
2307 AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileStream, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS,
2308 &pStreamCC->State.Cfg.Props);
2309 if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileDMA))
2310 AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileDMA, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS,
2311 &pStreamCC->State.Cfg.Props);
2312 }
2313
2314 /* Do the actual enabling (won't fail as long as pSink is valid). */
2315 rc = AudioMixerSinkStart(pSink);
2316 }
2317 }
2318 /*
2319 * Disable
2320 */
2321 else
2322 {
2323 rc = AudioMixerSinkDrainAndStop(pSink, pStreamCC->State.pCircBuf ? (uint32_t)RTCircBufUsed(pStreamCC->State.pCircBuf) : 0);
2324 ichac97R3StreamTearDown(pStream);
2325 }
2326
2327 /* Make sure to leave the lock before (eventually) starting the timer. */
2328 AudioMixerSinkUnlock(pSink);
2329 ichac97R3StreamUnlock(pStreamCC);
2330 LogFunc(("[SD%RU8] fEnable=%RTbool, rc=%Rrc\n", pStream->u8SD, fEnable, rc));
2331 return rc;
2332}
2333
2334
2335/**
2336 * Returns whether an AC'97 stream is enabled or not.
2337 *
2338 * Only used by ichac97R3SaveExec().
2339 *
2340 * @returns VBox status code.
2341 * @param pThisCC The ring-3 AC'97 device state.
2342 * @param pStream Stream to return status for.
2343 */
2344static bool ichac97R3StreamIsEnabled(PAC97STATER3 pThisCC, PAC97STREAM pStream)
2345{
2346 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD);
2347 bool fIsEnabled = pSink && (AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING);
2348
2349 LogFunc(("[SD%RU8] fIsEnabled=%RTbool\n", pStream->u8SD, fIsEnabled));
2350 return fIsEnabled;
2351}
2352
2353
2354/**
2355 * Terminates an AC'97 audio stream (VM destroy).
2356 *
2357 * This is called by ichac97R3StreamsDestroy during VM poweroff & destruction.
2358 *
2359 * @returns VBox status code.
2360 * @param pThisCC The ring-3 AC'97 state.
2361 * @param pStream The AC'97 stream to destroy (shared).
2362 * @param pStreamCC The AC'97 stream to destroy (ring-3).
2363 * @sa ichac97R3StreamConstruct
2364 */
2365static void ichac97R3StreamDestroy(PAC97STATER3 pThisCC, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)
2366{
2367 LogFlowFunc(("[SD%RU8]\n", pStream->u8SD));
2368
2369 ichac97R3StreamTearDown(pStream);
2370
2371 int rc2 = RTCritSectDelete(&pStreamCC->State.CritSect);
2372 AssertRC(rc2);
2373
2374 if (pStreamCC->State.fRegisteredAsyncUpdateJob)
2375 {
2376 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD);
2377 if (pSink)
2378 AudioMixerSinkRemoveUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC);
2379 pStreamCC->State.fRegisteredAsyncUpdateJob = false;
2380 }
2381
2382 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))
2383 { /* likely */ }
2384 else
2385 {
2386 AudioHlpFileDestroy(pStreamCC->Dbg.Runtime.pFileStream);
2387 pStreamCC->Dbg.Runtime.pFileStream = NULL;
2388
2389 AudioHlpFileDestroy(pStreamCC->Dbg.Runtime.pFileDMA);
2390 pStreamCC->Dbg.Runtime.pFileDMA = NULL;
2391 }
2392
2393 if (pStreamCC->State.pCircBuf)
2394 {
2395 RTCircBufDestroy(pStreamCC->State.pCircBuf);
2396 pStreamCC->State.pCircBuf = NULL;
2397 }
2398
2399 LogFlowFuncLeave();
2400}
2401
2402
2403/**
2404 * Initializes an AC'97 audio stream (VM construct).
2405 *
2406 * This is only called by ichac97R3Construct.
2407 *
2408 * @returns VBox status code.
2409 * @param pThisCC The ring-3 AC'97 state.
2410 * @param pStream The AC'97 stream to create (shared).
2411 * @param pStreamCC The AC'97 stream to create (ring-3).
2412 * @param u8SD Stream descriptor number to assign.
2413 * @sa ichac97R3StreamDestroy
2414 */
2415static int ichac97R3StreamConstruct(PAC97STATER3 pThisCC, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, uint8_t u8SD)
2416{
2417 LogFunc(("[SD%RU8] pStream=%p\n", u8SD, pStream));
2418
2419 AssertReturn(u8SD < AC97_MAX_STREAMS, VERR_INVALID_PARAMETER);
2420 pStream->u8SD = u8SD;
2421 pStreamCC->u8SD = u8SD;
2422
2423 int rc = RTCritSectInit(&pStreamCC->State.CritSect);
2424 AssertRCReturn(rc, rc);
2425
2426 pStreamCC->Dbg.Runtime.fEnabled = pThisCC->Dbg.fEnabled;
2427
2428 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))
2429 { /* likely */ }
2430 else
2431 {
2432 char szFile[64];
2433 if (ichac97R3GetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)
2434 RTStrPrintf(szFile, sizeof(szFile), "ac97StreamWriteSD%RU8", pStream->u8SD);
2435 else
2436 RTStrPrintf(szFile, sizeof(szFile), "ac97StreamReadSD%RU8", pStream->u8SD);
2437
2438 char szPath[RTPATH_MAX];
2439 int rc2 = AudioHlpFileNameGet(szPath, sizeof(szPath), pThisCC->Dbg.pszOutPath, szFile,
2440 0 /* uInst */, AUDIOHLPFILETYPE_WAV, AUDIOHLPFILENAME_FLAGS_NONE);
2441 AssertRC(rc2);
2442 rc2 = AudioHlpFileCreate(AUDIOHLPFILETYPE_WAV, szPath, AUDIOHLPFILE_FLAGS_NONE, &pStreamCC->Dbg.Runtime.pFileStream);
2443 AssertRC(rc2);
2444
2445 if (ichac97R3GetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)
2446 RTStrPrintf(szFile, sizeof(szFile), "ac97DMAWriteSD%RU8", pStream->u8SD);
2447 else
2448 RTStrPrintf(szFile, sizeof(szFile), "ac97DMAReadSD%RU8", pStream->u8SD);
2449
2450 rc2 = AudioHlpFileNameGet(szPath, sizeof(szPath), pThisCC->Dbg.pszOutPath, szFile,
2451 0 /* uInst */, AUDIOHLPFILETYPE_WAV, AUDIOHLPFILENAME_FLAGS_NONE);
2452 AssertRC(rc2);
2453
2454 rc2 = AudioHlpFileCreate(AUDIOHLPFILETYPE_WAV, szPath, AUDIOHLPFILE_FLAGS_NONE, &pStreamCC->Dbg.Runtime.pFileDMA);
2455 AssertRC(rc2);
2456
2457 /* Delete stale debugging files from a former run. */
2458 AudioHlpFileDelete(pStreamCC->Dbg.Runtime.pFileStream);
2459 AudioHlpFileDelete(pStreamCC->Dbg.Runtime.pFileDMA);
2460 }
2461
2462 return rc;
2463}
2464
2465#endif /* IN_RING3 */
2466
2467
2468/*********************************************************************************************************************************
2469* NABM I/O Port Handlers (Global + Stream) *
2470*********************************************************************************************************************************/
2471
2472/**
2473 * @callback_method_impl{FNIOMIOPORTNEWIN}
2474 */
2475static DECLCALLBACK(VBOXSTRICTRC)
2476ichac97IoPortNabmRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
2477{
2478 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
2479 RT_NOREF(pvUser);
2480
2481 DEVAC97_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_IOPORT_READ);
2482
2483 /* Get the index of the NABMBAR port. */
2484 if ( AC97_PORT2IDX_UNMASKED(offPort) < AC97_MAX_STREAMS
2485 && offPort != AC97_GLOB_CNT)
2486 {
2487 PAC97STREAM pStream = &pThis->aStreams[AC97_PORT2IDX(offPort)];
2488 PAC97BMREGS pRegs = &pStream->Regs;
2489
2490 switch (cb)
2491 {
2492 case 1:
2493 switch (offPort & AC97_NABM_OFF_MASK)
2494 {
2495 case AC97_NABM_OFF_CIV:
2496 /* Current Index Value Register */
2497 *pu32 = pRegs->civ;
2498 Log3Func(("CIV[%d] -> %#x\n", AC97_PORT2IDX(offPort), *pu32));
2499 break;
2500 case AC97_NABM_OFF_LVI:
2501 /* Last Valid Index Register */
2502 *pu32 = pRegs->lvi;
2503 Log3Func(("LVI[%d] -> %#x\n", AC97_PORT2IDX(offPort), *pu32));
2504 break;
2505 case AC97_NABM_OFF_PIV:
2506 /* Prefetched Index Value Register */
2507 *pu32 = pRegs->piv;
2508 Log3Func(("PIV[%d] -> %#x\n", AC97_PORT2IDX(offPort), *pu32));
2509 break;
2510 case AC97_NABM_OFF_CR:
2511 /* Control Register */
2512 *pu32 = pRegs->cr;
2513 Log3Func(("CR[%d] -> %#x\n", AC97_PORT2IDX(offPort), *pu32));
2514 break;
2515 case AC97_NABM_OFF_SR:
2516 /* Status Register (lower part) */
2517 *pu32 = RT_LO_U8(pRegs->sr);
2518 Log3Func(("SRb[%d] -> %#x\n", AC97_PORT2IDX(offPort), *pu32));
2519 break;
2520 default:
2521 *pu32 = UINT32_MAX;
2522 LogFunc(("U nabm readb %#x -> %#x\n", offPort, UINT32_MAX));
2523 STAM_REL_COUNTER_INC(&pThis->StatUnimplementedNabmReads);
2524 break;
2525 }
2526 break;
2527
2528 case 2:
2529 switch (offPort & AC97_NABM_OFF_MASK)
2530 {
2531 case AC97_NABM_OFF_SR:
2532 /* Status Register */
2533 *pu32 = pRegs->sr;
2534 Log3Func(("SR[%d] -> %#x\n", AC97_PORT2IDX(offPort), *pu32));
2535 break;
2536 case AC97_NABM_OFF_PICB:
2537 /* Position in Current Buffer */
2538 *pu32 = pRegs->picb;
2539 Log3Func(("PICB[%d] -> %#x\n", AC97_PORT2IDX(offPort), *pu32));
2540 break;
2541 default:
2542 *pu32 = UINT32_MAX;
2543 LogFunc(("U nabm readw %#x -> %#x\n", offPort, UINT32_MAX));
2544 STAM_REL_COUNTER_INC(&pThis->StatUnimplementedNabmReads);
2545 break;
2546 }
2547 break;
2548
2549 case 4:
2550 switch (offPort & AC97_NABM_OFF_MASK)
2551 {
2552 case AC97_NABM_OFF_BDBAR:
2553 /* Buffer Descriptor Base Address Register */
2554 *pu32 = pRegs->bdbar;
2555 Log3Func(("BMADDR[%d] -> %#x\n", AC97_PORT2IDX(offPort), *pu32));
2556 break;
2557 case AC97_NABM_OFF_CIV:
2558 /* 32-bit access: Current Index Value Register +
2559 * Last Valid Index Register +
2560 * Status Register */
2561 *pu32 = pRegs->civ | ((uint32_t)pRegs->lvi << 8) | ((uint32_t)pRegs->sr << 16);
2562 Log3Func(("CIV LVI SR[%d] -> %#x, %#x, %#x\n",
2563 AC97_PORT2IDX(offPort), pRegs->civ, pRegs->lvi, pRegs->sr));
2564 break;
2565 case AC97_NABM_OFF_PICB:
2566 /* 32-bit access: Position in Current Buffer Register +
2567 * Prefetched Index Value Register +
2568 * Control Register */
2569 *pu32 = pRegs->picb | ((uint32_t)pRegs->piv << 16) | ((uint32_t)pRegs->cr << 24);
2570 Log3Func(("PICB PIV CR[%d] -> %#x %#x %#x %#x\n",
2571 AC97_PORT2IDX(offPort), *pu32, pRegs->picb, pRegs->piv, pRegs->cr));
2572 break;
2573
2574 default:
2575 *pu32 = UINT32_MAX;
2576 LogFunc(("U nabm readl %#x -> %#x\n", offPort, UINT32_MAX));
2577 STAM_REL_COUNTER_INC(&pThis->StatUnimplementedNabmReads);
2578 break;
2579 }
2580 break;
2581
2582 default:
2583 DEVAC97_UNLOCK(pDevIns, pThis);
2584 AssertFailed();
2585 return VERR_IOM_IOPORT_UNUSED;
2586 }
2587 }
2588 else
2589 {
2590 switch (cb)
2591 {
2592 case 1:
2593 switch (offPort)
2594 {
2595 case AC97_CAS:
2596 /* Codec Access Semaphore Register */
2597 Log3Func(("CAS %d\n", pThis->cas));
2598 *pu32 = pThis->cas;
2599 pThis->cas = 1;
2600 break;
2601 default:
2602 *pu32 = UINT32_MAX;
2603 LogFunc(("U nabm readb %#x -> %#x\n", offPort, UINT32_MAX));
2604 STAM_REL_COUNTER_INC(&pThis->StatUnimplementedNabmReads);
2605 break;
2606 }
2607 break;
2608
2609 case 2:
2610 *pu32 = UINT32_MAX;
2611 LogFunc(("U nabm readw %#x -> %#x\n", offPort, UINT32_MAX));
2612 STAM_REL_COUNTER_INC(&pThis->StatUnimplementedNabmReads);
2613 break;
2614
2615 case 4:
2616 switch (offPort)
2617 {
2618 case AC97_GLOB_CNT:
2619 /* Global Control */
2620 *pu32 = pThis->glob_cnt;
2621 Log3Func(("glob_cnt -> %#x\n", *pu32));
2622 break;
2623 case AC97_GLOB_STA:
2624 /* Global Status */
2625 *pu32 = pThis->glob_sta | AC97_GS_S0CR;
2626 Log3Func(("glob_sta -> %#x\n", *pu32));
2627 break;
2628 default:
2629 *pu32 = UINT32_MAX;
2630 LogFunc(("U nabm readl %#x -> %#x\n", offPort, UINT32_MAX));
2631 STAM_REL_COUNTER_INC(&pThis->StatUnimplementedNabmReads);
2632 break;
2633 }
2634 break;
2635
2636 default:
2637 DEVAC97_UNLOCK(pDevIns, pThis);
2638 AssertFailed();
2639 return VERR_IOM_IOPORT_UNUSED;
2640 }
2641 }
2642
2643 DEVAC97_UNLOCK(pDevIns, pThis);
2644 return VINF_SUCCESS;
2645}
2646
2647
2648/**
2649 * @callback_method_impl{FNIOMIOPORTNEWOUT}
2650 */
2651static DECLCALLBACK(VBOXSTRICTRC)
2652ichac97IoPortNabmWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
2653{
2654 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
2655#ifdef IN_RING3
2656 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
2657#endif
2658 RT_NOREF(pvUser);
2659
2660 VBOXSTRICTRC rc = VINF_SUCCESS;
2661 if ( AC97_PORT2IDX_UNMASKED(offPort) < AC97_MAX_STREAMS
2662 && offPort != AC97_GLOB_CNT)
2663 {
2664#ifdef IN_RING3
2665 PAC97STREAMR3 pStreamCC = &pThisCC->aStreams[AC97_PORT2IDX(offPort)];
2666#endif
2667 PAC97STREAM pStream = &pThis->aStreams[AC97_PORT2IDX(offPort)];
2668 PAC97BMREGS pRegs = &pStream->Regs;
2669
2670 /** @todo r=bird: this locking is overkill, we don't need the timer lock
2671 * unless we're going to call ichac97R3TimerSet. */
2672 DEVAC97_LOCK_BOTH_RETURN(pDevIns, pThis, pStream, VINF_IOM_R3_IOPORT_WRITE);
2673 switch (cb)
2674 {
2675 case 1:
2676 switch (offPort & AC97_NABM_OFF_MASK)
2677 {
2678 /*
2679 * Last Valid Index.
2680 */
2681 case AC97_NABM_OFF_LVI:
2682 if ( (pRegs->cr & AC97_CR_RPBM)
2683 && (pRegs->sr & AC97_SR_DCH))
2684 {
2685#ifdef IN_RING3 /** @todo r=bird: What kind of unexplained non-sense is this ifdef?!? */
2686 pRegs->sr &= ~(AC97_SR_DCH | AC97_SR_CELV);
2687 pRegs->civ = pRegs->piv;
2688 pRegs->piv = (pRegs->piv + 1) % AC97_MAX_BDLE;
2689#else
2690 rc = VINF_IOM_R3_IOPORT_WRITE;
2691#endif
2692 }
2693 pRegs->lvi = u32 % AC97_MAX_BDLE;
2694 Log3Func(("[SD%RU8] LVI <- %#x\n", pStream->u8SD, u32));
2695 break;
2696
2697 /*
2698 * Control Registers.
2699 */
2700 case AC97_NABM_OFF_CR:
2701#ifdef IN_RING3
2702 Log3Func(("[SD%RU8] CR <- %#x (cr %#x)\n", pStream->u8SD, u32, pRegs->cr));
2703 if (u32 & AC97_CR_RR) /* Busmaster reset. */
2704 {
2705 Log3Func(("[SD%RU8] Reset\n", pStream->u8SD));
2706
2707 /* Make sure that Run/Pause Bus Master bit (RPBM) is cleared (0). */
2708 Assert((pRegs->cr & AC97_CR_RPBM) == 0);
2709 if (pRegs->cr & AC97_CR_RPBM)
2710 ichac97R3StreamEnable(pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fEnable */);
2711
2712 ichac97R3StreamReset(pThis, pStream, pStreamCC);
2713
2714 ichac97StreamUpdateSR(pDevIns, pThis, pStream, AC97_SR_DCH); /** @todo Do we need to do that? */
2715 }
2716 else
2717 {
2718 pRegs->cr = u32 & AC97_CR_VALID_MASK;
2719
2720 if (!(pRegs->cr & AC97_CR_RPBM))
2721 {
2722 Log3Func(("[SD%RU8] Disable\n", pStream->u8SD));
2723
2724 ichac97R3StreamEnable(pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fEnable */);
2725
2726 pRegs->sr |= AC97_SR_DCH;
2727 }
2728 else
2729 {
2730 Log3Func(("[SD%RU8] Enable\n", pStream->u8SD));
2731
2732 pRegs->sr &= ~AC97_SR_DCH;
2733
2734 if (ichac97R3StreamFetchNextBdle(pDevIns, pStream, pStreamCC))
2735 ichac97StreamUpdateSR(pDevIns, pThis, pStream, pRegs->sr | AC97_SR_BCIS);
2736# ifdef LOG_ENABLED
2737 if (LogIsFlowEnabled())
2738 ichac97R3DbgPrintBdl(pDevIns, pThis, pStream, DBGFR3InfoLogHlp(), "ichac97IoPortNabmWrite: ");
2739# endif
2740 ichac97R3StreamEnable(pDevIns, pThis, pThisCC, pStream, pStreamCC, true /* fEnable */);
2741
2742 /* Arm the timer for this stream. */
2743 ichac97R3TimerSet(pDevIns, pStream, pStreamCC->State.cTransferTicks);
2744 }
2745 }
2746#else /* !IN_RING3 */
2747 rc = VINF_IOM_R3_IOPORT_WRITE;
2748#endif
2749 break;
2750
2751 /*
2752 * Status Registers.
2753 */
2754 case AC97_NABM_OFF_SR:
2755 ichac97StreamWriteSR(pDevIns, pThis, pStream, u32);
2756 break;
2757
2758 default:
2759 LogRel2(("AC97: Warning: Unimplemented NABMWrite offPort=%#x <- %#x LB 1\n", offPort, u32));
2760 STAM_REL_COUNTER_INC(&pThis->StatUnimplementedNabmWrites);
2761 break;
2762 }
2763 break;
2764
2765 case 2:
2766 switch (offPort & AC97_NABM_OFF_MASK)
2767 {
2768 case AC97_NABM_OFF_SR:
2769 ichac97StreamWriteSR(pDevIns, pThis, pStream, u32);
2770 break;
2771 default:
2772 LogRel2(("AC97: Warning: Unimplemented NABMWrite offPort=%#x <- %#x LB 2\n", offPort, u32));
2773 STAM_REL_COUNTER_INC(&pThis->StatUnimplementedNabmWrites);
2774 break;
2775 }
2776 break;
2777
2778 case 4:
2779 switch (offPort & AC97_NABM_OFF_MASK)
2780 {
2781 case AC97_NABM_OFF_BDBAR:
2782 /* Buffer Descriptor list Base Address Register */
2783 pRegs->bdbar = u32 & ~(uint32_t)3;
2784 Log3Func(("[SD%RU8] BDBAR <- %#x (bdbar %#x)\n", AC97_PORT2IDX(offPort), u32, pRegs->bdbar));
2785 break;
2786 default:
2787 LogRel2(("AC97: Warning: Unimplemented NABMWrite offPort=%#x <- %#x LB 4\n", offPort, u32));
2788 STAM_REL_COUNTER_INC(&pThis->StatUnimplementedNabmWrites);
2789 break;
2790 }
2791 break;
2792
2793 default:
2794 AssertMsgFailed(("offPort=%#x <- %#x LB %u\n", offPort, u32, cb));
2795 break;
2796 }
2797 DEVAC97_UNLOCK_BOTH(pDevIns, pThis, pStream);
2798 }
2799 else
2800 {
2801 switch (cb)
2802 {
2803 case 1:
2804 LogRel2(("AC97: Warning: Unimplemented NABMWrite offPort=%#x <- %#x LB 1\n", offPort, u32));
2805 STAM_REL_COUNTER_INC(&pThis->StatUnimplementedNabmWrites);
2806 break;
2807
2808 case 2:
2809 LogRel2(("AC97: Warning: Unimplemented NABMWrite offPort=%#x <- %#x LB 2\n", offPort, u32));
2810 STAM_REL_COUNTER_INC(&pThis->StatUnimplementedNabmWrites);
2811 break;
2812
2813 case 4:
2814 switch (offPort)
2815 {
2816 case AC97_GLOB_CNT:
2817 /* Global Control */
2818 DEVAC97_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_IOPORT_WRITE);
2819 if (u32 & AC97_GC_WR)
2820 ichac97WarmReset(pThis);
2821 if (u32 & AC97_GC_CR)
2822 ichac97ColdReset(pThis);
2823 if (!(u32 & (AC97_GC_WR | AC97_GC_CR)))
2824 pThis->glob_cnt = u32 & AC97_GC_VALID_MASK;
2825 Log3Func(("glob_cnt <- %#x (glob_cnt %#x)\n", u32, pThis->glob_cnt));
2826 DEVAC97_UNLOCK(pDevIns, pThis);
2827 break;
2828 case AC97_GLOB_STA:
2829 /* Global Status */
2830 DEVAC97_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_IOPORT_WRITE);
2831 pThis->glob_sta &= ~(u32 & AC97_GS_WCLEAR_MASK);
2832 pThis->glob_sta |= (u32 & ~(AC97_GS_WCLEAR_MASK | AC97_GS_RO_MASK)) & AC97_GS_VALID_MASK;
2833 Log3Func(("glob_sta <- %#x (glob_sta %#x)\n", u32, pThis->glob_sta));
2834 DEVAC97_UNLOCK(pDevIns, pThis);
2835 break;
2836 default:
2837 LogRel2(("AC97: Warning: Unimplemented NABMWrite offPort=%#x <- %#x LB 4\n", offPort, u32));
2838 STAM_REL_COUNTER_INC(&pThis->StatUnimplementedNabmWrites);
2839 break;
2840 }
2841 break;
2842
2843 default:
2844 AssertMsgFailed(("offPort=%#x <- %#x LB %u\n", offPort, u32, cb));
2845 break;
2846 }
2847 }
2848
2849 return rc;
2850}
2851
2852
2853/*********************************************************************************************************************************
2854* Mixer & NAM I/O handlers *
2855*********************************************************************************************************************************/
2856
2857/**
2858 * Sets a AC'97 mixer control to a specific value.
2859 *
2860 * @returns VBox status code.
2861 * @param pThis The shared AC'97 state.
2862 * @param uMixerIdx Mixer control to set value for.
2863 * @param uVal Value to set.
2864 */
2865static void ichac97MixerSet(PAC97STATE pThis, uint8_t uMixerIdx, uint16_t uVal)
2866{
2867 AssertMsgReturnVoid(uMixerIdx + 2U <= sizeof(pThis->mixer_data),
2868 ("Index %RU8 out of bounds (%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)));
2869
2870 LogRel2(("AC97: Setting mixer index #%RU8 to %RU16 (%RU8 %RU8)\n", uMixerIdx, uVal, RT_HI_U8(uVal), RT_LO_U8(uVal)));
2871
2872 pThis->mixer_data[uMixerIdx + 0] = RT_LO_U8(uVal);
2873 pThis->mixer_data[uMixerIdx + 1] = RT_HI_U8(uVal);
2874}
2875
2876
2877/**
2878 * Gets a value from a specific AC'97 mixer control.
2879 *
2880 * @returns Retrieved mixer control value.
2881 * @param pThis The shared AC'97 state.
2882 * @param uMixerIdx Mixer control to get value for.
2883 */
2884static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t uMixerIdx)
2885{
2886 AssertMsgReturn(uMixerIdx + 2U <= sizeof(pThis->mixer_data),
2887 ("Index %RU8 out of bounds (%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)),
2888 UINT16_MAX);
2889 return RT_MAKE_U16(pThis->mixer_data[uMixerIdx + 0], pThis->mixer_data[uMixerIdx + 1]);
2890}
2891
2892#ifdef IN_RING3
2893
2894/**
2895 * Sets the volume of a specific AC'97 mixer control.
2896 *
2897 * This currently only supports attenuation -- gain support is currently not implemented.
2898 *
2899 * @returns VBox status code.
2900 * @param pThis The shared AC'97 state.
2901 * @param pThisCC The ring-3 AC'97 state.
2902 * @param index AC'97 mixer index to set volume for.
2903 * @param enmMixerCtl Corresponding audio mixer sink.
2904 * @param uVal Volume value to set.
2905 */
2906static int ichac97R3MixerSetVolume(PAC97STATE pThis, PAC97STATER3 pThisCC, int index, PDMAUDIOMIXERCTL enmMixerCtl, uint32_t uVal)
2907{
2908 /*
2909 * From AC'97 SoundMax Codec AD1981A/AD1981B:
2910 * "Because AC '97 defines 6-bit volume registers, to maintain compatibility whenever the
2911 * D5 or D13 bits are set to 1, their respective lower five volume bits are automatically
2912 * set to 1 by the Codec logic. On readback, all lower 5 bits will read ones whenever
2913 * these bits are set to 1."
2914 *
2915 * Linux ALSA depends on this behavior to detect that only 5 bits are used for volume
2916 * control and the optional 6th bit is not used. Note that this logic only applies to the
2917 * master volume controls.
2918 */
2919 if ( index == AC97_Master_Volume_Mute
2920 || index == AC97_Headphone_Volume_Mute
2921 || index == AC97_Master_Volume_Mono_Mute)
2922 {
2923 if (uVal & RT_BIT(5)) /* D5 bit set? */
2924 uVal |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
2925 if (uVal & RT_BIT(13)) /* D13 bit set? */
2926 uVal |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
2927 }
2928
2929 const bool fCtlMuted = (uVal >> AC97_BARS_VOL_MUTE_SHIFT) & 1;
2930 uint8_t uCtlAttLeft = (uVal >> 8) & AC97_BARS_VOL_MASK;
2931 uint8_t uCtlAttRight = uVal & AC97_BARS_VOL_MASK;
2932
2933 /* For the master and headphone volume, 0 corresponds to 0dB attenuation. For the other
2934 * volume controls, 0 means 12dB gain and 8 means unity gain.
2935 */
2936 if (index != AC97_Master_Volume_Mute && index != AC97_Headphone_Volume_Mute)
2937 {
2938# ifndef VBOX_WITH_AC97_GAIN_SUPPORT
2939 /* NB: Currently there is no gain support, only attenuation. */
2940 uCtlAttLeft = uCtlAttLeft < 8 ? 0 : uCtlAttLeft - 8;
2941 uCtlAttRight = uCtlAttRight < 8 ? 0 : uCtlAttRight - 8;
2942# endif
2943 }
2944 Assert(uCtlAttLeft <= 255 / AC97_DB_FACTOR);
2945 Assert(uCtlAttRight <= 255 / AC97_DB_FACTOR);
2946
2947 LogFunc(("index=0x%x, uVal=%RU32, enmMixerCtl=%RU32\n", index, uVal, enmMixerCtl));
2948 LogFunc(("uCtlAttLeft=%RU8, uCtlAttRight=%RU8 ", uCtlAttLeft, uCtlAttRight));
2949
2950 /*
2951 * For AC'97 volume controls, each additional step means -1.5dB attenuation with
2952 * zero being maximum. In contrast, we're internally using 255 (PDMAUDIO_VOLUME_MAX)
2953 * steps, each -0.375dB, where 0 corresponds to -96dB and 255 corresponds to 0dB.
2954 */
2955 uint8_t lVol = PDMAUDIO_VOLUME_MAX - uCtlAttLeft * AC97_DB_FACTOR;
2956 uint8_t rVol = PDMAUDIO_VOLUME_MAX - uCtlAttRight * AC97_DB_FACTOR;
2957
2958 Log(("-> fMuted=%RTbool, lVol=%RU8, rVol=%RU8\n", fCtlMuted, lVol, rVol));
2959
2960 int rc = VINF_SUCCESS;
2961
2962 if (pThisCC->pMixer) /* Device can be in reset state, so no mixer available. */
2963 {
2964 PDMAUDIOVOLUME Vol = { fCtlMuted, lVol, rVol };
2965 PAUDMIXSINK pSink = NULL;
2966
2967 switch (enmMixerCtl)
2968 {
2969 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
2970 rc = AudioMixerSetMasterVolume(pThisCC->pMixer, &Vol);
2971 break;
2972
2973 case PDMAUDIOMIXERCTL_FRONT:
2974 pSink = pThisCC->pSinkOut;
2975 break;
2976
2977 case PDMAUDIOMIXERCTL_MIC_IN:
2978 case PDMAUDIOMIXERCTL_LINE_IN:
2979 /* These are recognized but do nothing. */
2980 break;
2981
2982 default:
2983 AssertFailed();
2984 rc = VERR_NOT_SUPPORTED;
2985 break;
2986 }
2987
2988 if (pSink)
2989 rc = AudioMixerSinkSetVolume(pSink, &Vol);
2990 }
2991
2992 ichac97MixerSet(pThis, index, uVal);
2993
2994 if (RT_FAILURE(rc))
2995 LogFlowFunc(("Failed with %Rrc\n", rc));
2996
2997 return rc;
2998}
2999
3000/**
3001 * Sets the gain of a specific AC'97 recording control.
3002 *
3003 * @note Gain support is currently not implemented in PDM audio.
3004 *
3005 * @returns VBox status code.
3006 * @param pThis The shared AC'97 state.
3007 * @param pThisCC The ring-3 AC'97 state.
3008 * @param index AC'97 mixer index to set volume for.
3009 * @param enmMixerCtl Corresponding audio mixer sink.
3010 * @param uVal Volume value to set.
3011 */
3012static int ichac97R3MixerSetGain(PAC97STATE pThis, PAC97STATER3 pThisCC, int index, PDMAUDIOMIXERCTL enmMixerCtl, uint32_t uVal)
3013{
3014 /*
3015 * For AC'97 recording controls, each additional step means +1.5dB gain with
3016 * zero being 0dB gain and 15 being +22.5dB gain.
3017 */
3018 bool const fCtlMuted = (uVal >> AC97_BARS_VOL_MUTE_SHIFT) & 1;
3019 uint8_t uCtlGainLeft = (uVal >> 8) & AC97_BARS_GAIN_MASK;
3020 uint8_t uCtlGainRight = uVal & AC97_BARS_GAIN_MASK;
3021
3022 Assert(uCtlGainLeft <= 255 / AC97_DB_FACTOR);
3023 Assert(uCtlGainRight <= 255 / AC97_DB_FACTOR);
3024
3025 LogFunc(("index=0x%x, uVal=%RU32, enmMixerCtl=%RU32\n", index, uVal, enmMixerCtl));
3026 LogFunc(("uCtlGainLeft=%RU8, uCtlGainRight=%RU8 ", uCtlGainLeft, uCtlGainRight));
3027
3028 uint8_t lVol = PDMAUDIO_VOLUME_MAX + uCtlGainLeft * AC97_DB_FACTOR;
3029 uint8_t rVol = PDMAUDIO_VOLUME_MAX + uCtlGainRight * AC97_DB_FACTOR;
3030
3031 /* We do not currently support gain. Since AC'97 does not support attenuation
3032 * for the recording input, the best we can do is set the maximum volume.
3033 */
3034# ifndef VBOX_WITH_AC97_GAIN_SUPPORT
3035 /* NB: Currently there is no gain support, only attenuation. Since AC'97 does not
3036 * support attenuation for the recording inputs, the best we can do is set the
3037 * maximum volume.
3038 */
3039 lVol = rVol = PDMAUDIO_VOLUME_MAX;
3040# endif
3041
3042 Log(("-> fMuted=%RTbool, lVol=%RU8, rVol=%RU8\n", fCtlMuted, lVol, rVol));
3043
3044 int rc = VINF_SUCCESS;
3045
3046 if (pThisCC->pMixer) /* Device can be in reset state, so no mixer available. */
3047 {
3048 PDMAUDIOVOLUME Vol = { fCtlMuted, lVol, rVol };
3049 PAUDMIXSINK pSink = NULL;
3050
3051 switch (enmMixerCtl)
3052 {
3053 case PDMAUDIOMIXERCTL_MIC_IN:
3054 pSink = pThisCC->pSinkMicIn;
3055 break;
3056
3057 case PDMAUDIOMIXERCTL_LINE_IN:
3058 pSink = pThisCC->pSinkLineIn;
3059 break;
3060
3061 default:
3062 AssertFailed();
3063 rc = VERR_NOT_SUPPORTED;
3064 break;
3065 }
3066
3067 if (pSink) {
3068 rc = AudioMixerSinkSetVolume(pSink, &Vol);
3069 /* There is only one AC'97 recording gain control. If line in
3070 * is changed, also update the microphone. If the optional dedicated
3071 * microphone is changed, only change that.
3072 * NB: The codecs we support do not have the dedicated microphone control.
3073 */
3074 if ((pSink == pThisCC->pSinkLineIn) && pThisCC->pSinkMicIn)
3075 rc = AudioMixerSinkSetVolume(pSink, &Vol);
3076 }
3077 }
3078
3079 ichac97MixerSet(pThis, index, uVal);
3080
3081 if (RT_FAILURE(rc))
3082 LogFlowFunc(("Failed with %Rrc\n", rc));
3083
3084 return rc;
3085}
3086
3087
3088/**
3089 * Converts an AC'97 recording source index to a PDM audio recording source.
3090 *
3091 * @returns PDM audio recording source.
3092 * @param uIdx AC'97 index to convert.
3093 */
3094static PDMAUDIOPATH ichac97R3IdxToRecSource(uint8_t uIdx)
3095{
3096 switch (uIdx)
3097 {
3098 case AC97_REC_MIC: return PDMAUDIOPATH_IN_MIC;
3099 case AC97_REC_CD: return PDMAUDIOPATH_IN_CD;
3100 case AC97_REC_VIDEO: return PDMAUDIOPATH_IN_VIDEO;
3101 case AC97_REC_AUX: return PDMAUDIOPATH_IN_AUX;
3102 case AC97_REC_LINE_IN: return PDMAUDIOPATH_IN_LINE;
3103 case AC97_REC_PHONE: return PDMAUDIOPATH_IN_PHONE;
3104 default:
3105 break;
3106 }
3107
3108 LogFlowFunc(("Unknown record source %d, using MIC\n", uIdx));
3109 return PDMAUDIOPATH_IN_MIC;
3110}
3111
3112
3113/**
3114 * Converts a PDM audio recording source to an AC'97 recording source index.
3115 *
3116 * @returns AC'97 recording source index.
3117 * @param enmRecSrc PDM audio recording source to convert.
3118 */
3119static uint8_t ichac97R3RecSourceToIdx(PDMAUDIOPATH enmRecSrc)
3120{
3121 switch (enmRecSrc)
3122 {
3123 case PDMAUDIOPATH_IN_MIC: return AC97_REC_MIC;
3124 case PDMAUDIOPATH_IN_CD: return AC97_REC_CD;
3125 case PDMAUDIOPATH_IN_VIDEO: return AC97_REC_VIDEO;
3126 case PDMAUDIOPATH_IN_AUX: return AC97_REC_AUX;
3127 case PDMAUDIOPATH_IN_LINE: return AC97_REC_LINE_IN;
3128 case PDMAUDIOPATH_IN_PHONE: return AC97_REC_PHONE;
3129 default:
3130 AssertMsgFailedBreak(("%d\n", enmRecSrc));
3131 }
3132
3133 LogFlowFunc(("Unknown audio recording source %d using MIC\n", enmRecSrc));
3134 return AC97_REC_MIC;
3135}
3136
3137
3138/**
3139 * Performs an AC'97 mixer record select to switch to a different recording
3140 * source.
3141 *
3142 * @param pThis The shared AC'97 state.
3143 * @param val AC'97 recording source index to set.
3144 */
3145static void ichac97R3MixerRecordSelect(PAC97STATE pThis, uint32_t val)
3146{
3147 uint8_t rs = val & AC97_REC_MASK;
3148 uint8_t ls = (val >> 8) & AC97_REC_MASK;
3149
3150 PDMAUDIOPATH const ars = ichac97R3IdxToRecSource(rs);
3151 PDMAUDIOPATH const als = ichac97R3IdxToRecSource(ls);
3152
3153 rs = ichac97R3RecSourceToIdx(ars);
3154 ls = ichac97R3RecSourceToIdx(als);
3155
3156 LogRel(("AC97: Record select to left=%s, right=%s\n", PDMAudioPathGetName(ars), PDMAudioPathGetName(als)));
3157
3158 ichac97MixerSet(pThis, AC97_Record_Select, rs | (ls << 8));
3159}
3160
3161/**
3162 * Resets the AC'97 mixer.
3163 *
3164 * @returns VBox status code.
3165 * @param pThis The shared AC'97 state.
3166 * @param pThisCC The ring-3 AC'97 state.
3167 */
3168static int ichac97R3MixerReset(PAC97STATE pThis, PAC97STATER3 pThisCC)
3169{
3170 LogFlowFuncEnter();
3171
3172 RT_ZERO(pThis->mixer_data);
3173
3174 /* Note: Make sure to reset all registers first before bailing out on error. */
3175
3176 ichac97MixerSet(pThis, AC97_Reset , 0x0000); /* 6940 */
3177 ichac97MixerSet(pThis, AC97_Master_Volume_Mono_Mute , 0x8000);
3178 ichac97MixerSet(pThis, AC97_PC_BEEP_Volume_Mute , 0x0000);
3179
3180 ichac97MixerSet(pThis, AC97_Phone_Volume_Mute , 0x8008);
3181 ichac97MixerSet(pThis, AC97_Mic_Volume_Mute , 0x8008);
3182 ichac97MixerSet(pThis, AC97_CD_Volume_Mute , 0x8808);
3183 ichac97MixerSet(pThis, AC97_Aux_Volume_Mute , 0x8808);
3184 ichac97MixerSet(pThis, AC97_Record_Gain_Mic_Mute , 0x8000);
3185 ichac97MixerSet(pThis, AC97_General_Purpose , 0x0000);
3186 ichac97MixerSet(pThis, AC97_3D_Control , 0x0000);
3187 ichac97MixerSet(pThis, AC97_Powerdown_Ctrl_Stat , 0x000f);
3188
3189 /* Configure Extended Audio ID (EAID) + Control & Status (EACS) registers. */
3190 const uint16_t fEAID = AC97_EAID_REV1 | AC97_EACS_VRA | AC97_EACS_VRM; /* Our hardware is AC'97 rev2.3 compliant. */
3191 const uint16_t fEACS = AC97_EACS_VRA | AC97_EACS_VRM; /* Variable Rate PCM Audio (VRA) + Mic-In (VRM) capable. */
3192
3193 LogRel(("AC97: Mixer reset (EAID=0x%x, EACS=0x%x)\n", fEAID, fEACS));
3194
3195 ichac97MixerSet(pThis, AC97_Extended_Audio_ID, fEAID);
3196 ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, fEACS);
3197 ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate , 0xbb80 /* 48000 Hz by default */);
3198 ichac97MixerSet(pThis, AC97_PCM_Surround_DAC_Rate , 0xbb80 /* 48000 Hz by default */);
3199 ichac97MixerSet(pThis, AC97_PCM_LFE_DAC_Rate , 0xbb80 /* 48000 Hz by default */);
3200 ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate , 0xbb80 /* 48000 Hz by default */);
3201 ichac97MixerSet(pThis, AC97_MIC_ADC_Rate , 0xbb80 /* 48000 Hz by default */);
3202
3203 if (pThis->enmCodecModel == AC97CODEC_AD1980)
3204 {
3205 /* Analog Devices 1980 (AD1980) */
3206 ichac97MixerSet(pThis, AC97_Reset , 0x0010); /* Headphones. */
3207 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144);
3208 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5370);
3209 ichac97MixerSet(pThis, AC97_Headphone_Volume_Mute , 0x8000);
3210 }
3211 else if (pThis->enmCodecModel == AC97CODEC_AD1981B)
3212 {
3213 /* Analog Devices 1981B (AD1981B) */
3214 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144);
3215 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5374);
3216 }
3217 else
3218 {
3219 /* Sigmatel 9700 (STAC9700) */
3220 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x8384);
3221 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x7600); /* 7608 */
3222 }
3223 ichac97R3MixerRecordSelect(pThis, 0);
3224
3225 /* The default value is 8000h, which corresponds to 0 dB attenuation with mute on. */
3226 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER, 0x8000);
3227
3228 /* The default value for stereo registers is 8808h, which corresponds to 0 dB gain with mute on.*/
3229 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT, 0x8808);
3230 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808);
3231 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Mic_Volume_Mute, PDMAUDIOMIXERCTL_MIC_IN, 0x8008);
3232
3233 /* The default for record controls is 0 dB gain with mute on. */
3234 ichac97R3MixerSetGain(pThis, pThisCC, AC97_Record_Gain_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8000);
3235 ichac97R3MixerSetGain(pThis, pThisCC, AC97_Record_Gain_Mic_Mute, PDMAUDIOMIXERCTL_MIC_IN, 0x8000);
3236
3237 return VINF_SUCCESS;
3238}
3239
3240#endif /* IN_RING3 */
3241
3242/**
3243 * @callback_method_impl{FNIOMIOPORTNEWIN}
3244 */
3245static DECLCALLBACK(VBOXSTRICTRC)
3246ichac97IoPortNamRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
3247{
3248 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3249 RT_NOREF(pvUser);
3250 Assert(offPort < 256);
3251
3252 DEVAC97_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_IOPORT_READ);
3253
3254 VBOXSTRICTRC rc = VINF_SUCCESS;
3255 switch (cb)
3256 {
3257 case 1:
3258 LogRel2(("AC97: Warning: Unimplemented read (1 byte) offPort=%#x\n", offPort));
3259 pThis->cas = 0;
3260 *pu32 = UINT32_MAX;
3261 break;
3262
3263 case 2:
3264 pThis->cas = 0;
3265 *pu32 = ichac97MixerGet(pThis, offPort);
3266 break;
3267
3268 case 4:
3269 LogRel2(("AC97: Warning: Unimplemented read (4 bytes) offPort=%#x\n", offPort));
3270 pThis->cas = 0;
3271 *pu32 = UINT32_MAX;
3272 break;
3273
3274 default:
3275 AssertFailed();
3276 rc = VERR_IOM_IOPORT_UNUSED;
3277 break;
3278 }
3279
3280 DEVAC97_UNLOCK(pDevIns, pThis);
3281 return rc;
3282}
3283
3284/**
3285 * @callback_method_impl{FNIOMIOPORTNEWOUT}
3286 */
3287static DECLCALLBACK(VBOXSTRICTRC)
3288ichac97IoPortNamWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
3289{
3290 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3291#ifdef IN_RING3
3292 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
3293#endif
3294 RT_NOREF(pvUser);
3295
3296 DEVAC97_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_IOPORT_WRITE);
3297
3298 VBOXSTRICTRC rc = VINF_SUCCESS;
3299 switch (cb)
3300 {
3301 case 1:
3302 LogRel2(("AC97: Warning: Unimplemented NAMWrite (1 byte) offPort=%#x <- %#x\n", offPort, u32));
3303 pThis->cas = 0;
3304 break;
3305
3306 case 2:
3307 {
3308 pThis->cas = 0;
3309 switch (offPort)
3310 {
3311 case AC97_Reset:
3312#ifdef IN_RING3
3313 ichac97R3Reset(pDevIns);
3314#else
3315 rc = VINF_IOM_R3_IOPORT_WRITE;
3316#endif
3317 break;
3318 case AC97_Powerdown_Ctrl_Stat:
3319 u32 &= ~0xf;
3320 u32 |= ichac97MixerGet(pThis, offPort) & 0xf;
3321 ichac97MixerSet(pThis, offPort, u32);
3322 break;
3323 case AC97_Master_Volume_Mute:
3324 if (pThis->enmCodecModel == AC97CODEC_AD1980)
3325 {
3326 if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_LOSEL)
3327 break; /* Register controls surround (rear), do nothing. */
3328 }
3329#ifdef IN_RING3
3330 ichac97R3MixerSetVolume(pThis, pThisCC, offPort, PDMAUDIOMIXERCTL_VOLUME_MASTER, u32);
3331#else
3332 rc = VINF_IOM_R3_IOPORT_WRITE;
3333#endif
3334 break;
3335 case AC97_Headphone_Volume_Mute:
3336 if (pThis->enmCodecModel == AC97CODEC_AD1980)
3337 {
3338 if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_HPSEL)
3339 {
3340 /* Register controls PCM (front) outputs. */
3341#ifdef IN_RING3
3342 ichac97R3MixerSetVolume(pThis, pThisCC, offPort, PDMAUDIOMIXERCTL_VOLUME_MASTER, u32);
3343#else
3344 rc = VINF_IOM_R3_IOPORT_WRITE;
3345#endif
3346 }
3347 }
3348 break;
3349 case AC97_PCM_Out_Volume_Mute:
3350#ifdef IN_RING3
3351 ichac97R3MixerSetVolume(pThis, pThisCC, offPort, PDMAUDIOMIXERCTL_FRONT, u32);
3352#else
3353 rc = VINF_IOM_R3_IOPORT_WRITE;
3354#endif
3355 break;
3356 case AC97_Line_In_Volume_Mute:
3357#ifdef IN_RING3
3358 ichac97R3MixerSetVolume(pThis, pThisCC, offPort, PDMAUDIOMIXERCTL_LINE_IN, u32);
3359#else
3360 rc = VINF_IOM_R3_IOPORT_WRITE;
3361#endif
3362 break;
3363 case AC97_Record_Select:
3364#ifdef IN_RING3
3365 ichac97R3MixerRecordSelect(pThis, u32);
3366#else
3367 rc = VINF_IOM_R3_IOPORT_WRITE;
3368#endif
3369 break;
3370 case AC97_Record_Gain_Mute:
3371#ifdef IN_RING3
3372 /* Newer Ubuntu guests rely on that when controlling gain and muting
3373 * the recording (capturing) levels. */
3374 ichac97R3MixerSetGain(pThis, pThisCC, offPort, PDMAUDIOMIXERCTL_LINE_IN, u32);
3375#else
3376 rc = VINF_IOM_R3_IOPORT_WRITE;
3377#endif
3378 break;
3379 case AC97_Record_Gain_Mic_Mute:
3380#ifdef IN_RING3
3381 /* Ditto; see note above. */
3382 ichac97R3MixerSetGain(pThis, pThisCC, offPort, PDMAUDIOMIXERCTL_MIC_IN, u32);
3383#else
3384 rc = VINF_IOM_R3_IOPORT_WRITE;
3385#endif
3386 break;
3387 case AC97_Vendor_ID1:
3388 case AC97_Vendor_ID2:
3389 LogFunc(("Attempt to write vendor ID to %#x\n", u32));
3390 break;
3391 case AC97_Extended_Audio_ID:
3392 LogFunc(("Attempt to write extended audio ID to %#x\n", u32));
3393 break;
3394 case AC97_Extended_Audio_Ctrl_Stat:
3395#ifdef IN_RING3
3396 /*
3397 * Handle VRA bits.
3398 */
3399 if (!(u32 & AC97_EACS_VRA)) /* Check if VRA bit is not set. */
3400 {
3401 ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate, 0xbb80); /* Set default (48000 Hz). */
3402 /** @todo r=bird: Why reopen it now? Can't we put that off till it's
3403 * actually used? */
3404 ichac97R3StreamReSetUp(pDevIns, pThis, pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX],
3405 &pThisCC->aStreams[AC97SOUNDSOURCE_PO_INDEX], true /* fForce */);
3406
3407 ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate, 0xbb80); /* Set default (48000 Hz). */
3408 /** @todo r=bird: Why reopen it now? Can't we put that off till it's
3409 * actually used? */
3410 ichac97R3StreamReSetUp(pDevIns, pThis, pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX],
3411 &pThisCC->aStreams[AC97SOUNDSOURCE_PI_INDEX], true /* fForce */);
3412 }
3413 else
3414 LogRel2(("AC97: Variable rate audio (VRA) is not supported\n"));
3415
3416 /*
3417 * Handle VRM bits.
3418 */
3419 if (!(u32 & AC97_EACS_VRM)) /* Check if VRM bit is not set. */
3420 {
3421 ichac97MixerSet(pThis, AC97_MIC_ADC_Rate, 0xbb80); /* Set default (48000 Hz). */
3422 /** @todo r=bird: Why reopen it now? Can't we put that off till it's
3423 * actually used? */
3424 ichac97R3StreamReSetUp(pDevIns, pThis, pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX],
3425 &pThisCC->aStreams[AC97SOUNDSOURCE_MC_INDEX], true /* fForce */);
3426 }
3427 else
3428 LogRel2(("AC97: Variable rate microphone audio (VRM) is not supported\n"));
3429
3430 LogRel2(("AC97: Setting extended audio control to %#x\n", u32));
3431 ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, u32);
3432#else /* !IN_RING3 */
3433 rc = VINF_IOM_R3_IOPORT_WRITE;
3434#endif
3435 break;
3436 case AC97_PCM_Front_DAC_Rate: /* Output slots 3, 4, 6. */
3437#ifdef IN_RING3
3438 if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRA)
3439 {
3440 LogRel2(("AC97: Setting front DAC rate to 0x%x\n", u32));
3441 ichac97MixerSet(pThis, offPort, u32);
3442 /** @todo r=bird: Why reopen it now? Can't we put that off till it's
3443 * actually used? */
3444 ichac97R3StreamReSetUp(pDevIns, pThis, pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX],
3445 &pThisCC->aStreams[AC97SOUNDSOURCE_PO_INDEX], true /* fForce */);
3446 }
3447 else
3448 LogRel2(("AC97: Setting front DAC rate (0x%x) when VRA is not set is forbidden, ignoring\n", u32));
3449#else
3450 rc = VINF_IOM_R3_IOPORT_WRITE;
3451#endif
3452 break;
3453 case AC97_MIC_ADC_Rate: /* Input slot 6. */
3454#ifdef IN_RING3
3455 if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRM)
3456 {
3457 LogRel2(("AC97: Setting microphone ADC rate to 0x%x\n", u32));
3458 ichac97MixerSet(pThis, offPort, u32);
3459 /** @todo r=bird: Why reopen it now? Can't we put that off till it's
3460 * actually used? */
3461 ichac97R3StreamReSetUp(pDevIns, pThis, pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX],
3462 &pThisCC->aStreams[AC97SOUNDSOURCE_MC_INDEX], true /* fForce */);
3463 }
3464 else
3465 LogRel2(("AC97: Setting microphone ADC rate (0x%x) when VRM is not set is forbidden, ignoring\n", u32));
3466#else
3467 rc = VINF_IOM_R3_IOPORT_WRITE;
3468#endif
3469 break;
3470 case AC97_PCM_LR_ADC_Rate: /* Input slots 3, 4. */
3471#ifdef IN_RING3
3472 if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRA)
3473 {
3474 LogRel2(("AC97: Setting line-in ADC rate to 0x%x\n", u32));
3475 ichac97MixerSet(pThis, offPort, u32);
3476 /** @todo r=bird: Why reopen it now? Can't we put that off till it's
3477 * actually used? */
3478 ichac97R3StreamReSetUp(pDevIns, pThis, pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX],
3479 &pThisCC->aStreams[AC97SOUNDSOURCE_PI_INDEX], true /* fForce */);
3480 }
3481 else
3482 LogRel2(("AC97: Setting line-in ADC rate (0x%x) when VRA is not set is forbidden, ignoring\n", u32));
3483#else
3484 rc = VINF_IOM_R3_IOPORT_WRITE;
3485#endif
3486 break;
3487 default:
3488 LogRel2(("AC97: Warning: Unimplemented NAMWrite (2 bytes) offPort=%#x <- %#x\n", offPort, u32));
3489 ichac97MixerSet(pThis, offPort, u32);
3490 break;
3491 }
3492 break;
3493 }
3494
3495 case 4:
3496 LogRel2(("AC97: Warning: Unimplemented 4 byte NAMWrite: offPort=%#x <- %#x\n", offPort, u32));
3497 pThis->cas = 0;
3498 break;
3499
3500 default:
3501 AssertMsgFailed(("Unhandled NAMWrite offPort=%#x, cb=%u u32=%#x\n", offPort, cb, u32));
3502 break;
3503 }
3504
3505 DEVAC97_UNLOCK(pDevIns, pThis);
3506 return rc;
3507}
3508
3509#ifdef IN_RING3
3510
3511
3512/*********************************************************************************************************************************
3513* State Saving & Loading *
3514*********************************************************************************************************************************/
3515
3516/**
3517 * Saves (serializes) an AC'97 stream using SSM.
3518 *
3519 * @param pDevIns Device instance.
3520 * @param pSSM Saved state manager (SSM) handle to use.
3521 * @param pStream AC'97 stream to save.
3522 */
3523static void ichac97R3SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStream)
3524{
3525 PAC97BMREGS pRegs = &pStream->Regs;
3526 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3527
3528 pHlp->pfnSSMPutU32(pSSM, pRegs->bdbar);
3529 pHlp->pfnSSMPutU8( pSSM, pRegs->civ);
3530 pHlp->pfnSSMPutU8( pSSM, pRegs->lvi);
3531 pHlp->pfnSSMPutU16(pSSM, pRegs->sr);
3532 pHlp->pfnSSMPutU16(pSSM, pRegs->picb);
3533 pHlp->pfnSSMPutU8( pSSM, pRegs->piv);
3534 pHlp->pfnSSMPutU8( pSSM, pRegs->cr);
3535 pHlp->pfnSSMPutS32(pSSM, pRegs->bd_valid);
3536 pHlp->pfnSSMPutU32(pSSM, pRegs->bd.addr);
3537 pHlp->pfnSSMPutU32(pSSM, pRegs->bd.ctl_len);
3538}
3539
3540
3541/**
3542 * @callback_method_impl{FNSSMDEVSAVEEXEC}
3543 */
3544static DECLCALLBACK(int) ichac97R3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
3545{
3546 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3547 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
3548 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3549 LogFlowFuncEnter();
3550
3551 pHlp->pfnSSMPutU32(pSSM, pThis->glob_cnt);
3552 pHlp->pfnSSMPutU32(pSSM, pThis->glob_sta);
3553 pHlp->pfnSSMPutU32(pSSM, pThis->cas);
3554
3555 /*
3556 * The order that the streams are saved here is fixed, so don't change.
3557 */
3558 /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
3559 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
3560 ichac97R3SaveStream(pDevIns, pSSM, &pThis->aStreams[i]);
3561
3562 pHlp->pfnSSMPutMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
3563
3564 /* The stream order is against fixed and set in stone. */
3565 uint8_t afActiveStrms[AC97SOUNDSOURCE_MAX];
3566 afActiveStrms[AC97SOUNDSOURCE_PI_INDEX] = ichac97R3StreamIsEnabled(pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX]);
3567 afActiveStrms[AC97SOUNDSOURCE_PO_INDEX] = ichac97R3StreamIsEnabled(pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX]);
3568 afActiveStrms[AC97SOUNDSOURCE_MC_INDEX] = ichac97R3StreamIsEnabled(pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX]);
3569 AssertCompile(RT_ELEMENTS(afActiveStrms) == 3);
3570 pHlp->pfnSSMPutMem(pSSM, afActiveStrms, sizeof(afActiveStrms));
3571
3572 LogFlowFuncLeaveRC(VINF_SUCCESS);
3573 return VINF_SUCCESS;
3574}
3575
3576
3577/**
3578 * Loads an AC'97 stream from SSM.
3579 *
3580 * @returns VBox status code.
3581 * @param pDevIns The device instance.
3582 * @param pSSM Saved state manager (SSM) handle to use.
3583 * @param pStream AC'97 stream to load.
3584 */
3585static int ichac97R3LoadStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStream)
3586{
3587 PAC97BMREGS pRegs = &pStream->Regs;
3588 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3589
3590 pHlp->pfnSSMGetU32(pSSM, &pRegs->bdbar);
3591 pHlp->pfnSSMGetU8( pSSM, &pRegs->civ);
3592 pHlp->pfnSSMGetU8( pSSM, &pRegs->lvi);
3593 pHlp->pfnSSMGetU16(pSSM, &pRegs->sr);
3594 pHlp->pfnSSMGetU16(pSSM, &pRegs->picb);
3595 pHlp->pfnSSMGetU8( pSSM, &pRegs->piv);
3596 pHlp->pfnSSMGetU8( pSSM, &pRegs->cr);
3597 pHlp->pfnSSMGetS32(pSSM, &pRegs->bd_valid);
3598 pHlp->pfnSSMGetU32(pSSM, &pRegs->bd.addr);
3599 return pHlp->pfnSSMGetU32(pSSM, &pRegs->bd.ctl_len);
3600}
3601
3602
3603/**
3604 * @callback_method_impl{FNSSMDEVLOADEXEC}
3605 */
3606static DECLCALLBACK(int) ichac97R3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
3607{
3608 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3609 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
3610 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3611
3612 LogRel2(("ichac97LoadExec: uVersion=%RU32, uPass=0x%x\n", uVersion, uPass));
3613
3614 AssertMsgReturn (uVersion == AC97_SAVED_STATE_VERSION, ("%RU32\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
3615 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
3616
3617 pHlp->pfnSSMGetU32(pSSM, &pThis->glob_cnt);
3618 pHlp->pfnSSMGetU32(pSSM, &pThis->glob_sta);
3619 pHlp->pfnSSMGetU32(pSSM, &pThis->cas);
3620
3621 /*
3622 * The order the streams are loaded here is critical (defined by
3623 * AC97SOUNDSOURCE_XX_INDEX), so don't touch!
3624 */
3625 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
3626 {
3627 int rc = ichac97R3LoadStream(pDevIns, pSSM, &pThis->aStreams[i]);
3628 AssertRCReturn(rc, rc);
3629 }
3630
3631 pHlp->pfnSSMGetMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
3632
3633 ichac97R3MixerRecordSelect(pThis, ichac97MixerGet(pThis, AC97_Record_Select));
3634 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER,
3635 ichac97MixerGet(pThis, AC97_Master_Volume_Mute));
3636 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT,
3637 ichac97MixerGet(pThis, AC97_PCM_Out_Volume_Mute));
3638 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN,
3639 ichac97MixerGet(pThis, AC97_Line_In_Volume_Mute));
3640 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Mic_Volume_Mute, PDMAUDIOMIXERCTL_MIC_IN,
3641 ichac97MixerGet(pThis, AC97_Mic_Volume_Mute));
3642 ichac97R3MixerSetGain(pThis, pThisCC, AC97_Record_Gain_Mic_Mute, PDMAUDIOMIXERCTL_MIC_IN,
3643 ichac97MixerGet(pThis, AC97_Record_Gain_Mic_Mute));
3644 ichac97R3MixerSetGain(pThis, pThisCC, AC97_Record_Gain_Mute, PDMAUDIOMIXERCTL_LINE_IN,
3645 ichac97MixerGet(pThis, AC97_Record_Gain_Mute));
3646 if (pThis->enmCodecModel == AC97CODEC_AD1980)
3647 if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_HPSEL)
3648 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Headphone_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER,
3649 ichac97MixerGet(pThis, AC97_Headphone_Volume_Mute));
3650
3651 /*
3652 * Again the stream order is set is stone.
3653 */
3654 uint8_t afActiveStrms[AC97SOUNDSOURCE_MAX];
3655 int rc = pHlp->pfnSSMGetMem(pSSM, afActiveStrms, sizeof(afActiveStrms));
3656 AssertRCReturn(rc, rc);
3657
3658 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
3659 {
3660 const bool fEnable = RT_BOOL(afActiveStrms[i]);
3661 const PAC97STREAM pStream = &pThis->aStreams[i];
3662 const PAC97STREAMR3 pStreamCC = &pThisCC->aStreams[i];
3663
3664 rc = ichac97R3StreamEnable(pDevIns, pThis, pThisCC, pStream, pStreamCC, fEnable);
3665 AssertRC(rc);
3666 if ( fEnable
3667 && RT_SUCCESS(rc))
3668 {
3669 /* Re-arm the timer for this stream. */
3670 /** @todo r=aeichner This causes a VM hang upon saved state resume when NetBSD is used as a guest
3671 * Stopping the timer if cTransferTicks is 0 is a workaround but needs further investigation,
3672 * see @bugref{9759} for more information. */
3673 if (pStreamCC->State.cTransferTicks)
3674 ichac97R3TimerSet(pDevIns, pStream, pStreamCC->State.cTransferTicks);
3675 else
3676 PDMDevHlpTimerStop(pDevIns, pStream->hTimer);
3677 }
3678
3679 /* Keep going. */
3680 }
3681
3682 pThis->bup_flag = 0;
3683 pThis->last_samp = 0;
3684
3685 return VINF_SUCCESS;
3686}
3687
3688
3689/*********************************************************************************************************************************
3690* Debug Info Items *
3691*********************************************************************************************************************************/
3692
3693/** Used by ichac97R3DbgInfoStream and ichac97R3DbgInfoBDL. */
3694static int ichac97R3DbgLookupStrmIdx(PCDBGFINFOHLP pHlp, const char *pszArgs)
3695{
3696 if (pszArgs && *pszArgs)
3697 {
3698 int32_t idxStream;
3699 int rc = RTStrToInt32Full(pszArgs, 0, &idxStream);
3700 if (RT_SUCCESS(rc) && idxStream >= -1 && idxStream < AC97_MAX_STREAMS)
3701 return idxStream;
3702 pHlp->pfnPrintf(pHlp, "Argument '%s' is not a valid stream number!\n", pszArgs);
3703 }
3704 return -1;
3705}
3706
3707
3708/**
3709 * Generic buffer descriptor list dumper.
3710 */
3711static void ichac97R3DbgPrintBdl(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream,
3712 PCDBGFINFOHLP pHlp, const char *pszPrefix)
3713{
3714 uint8_t const bLvi = pStream->Regs.lvi;
3715 uint8_t const bCiv = pStream->Regs.civ;
3716 pHlp->pfnPrintf(pHlp, "%sBDL for stream #%u: @ %#RX32 LB 0x100; CIV=%#04x LVI=%#04x:\n",
3717 pszPrefix, pStream->u8SD, pStream->Regs.bdbar, bCiv, bLvi);
3718 if (pStream->Regs.bdbar != 0)
3719 {
3720 /* Read all in one go. */
3721 AC97BDLE aBdl[AC97_MAX_BDLE];
3722 RT_ZERO(aBdl);
3723 PDMDevHlpPCIPhysRead(pDevIns, pStream->Regs.bdbar, aBdl, sizeof(aBdl));
3724
3725 /* Get the audio props for the stream so we can translate the sizes correctly. */
3726 PDMAUDIOPCMPROPS Props;
3727 ichach97R3CalcStreamProps(pThis, pStream->u8SD, &Props);
3728
3729 /* Dump them. */
3730 uint64_t cbTotal = 0;
3731 uint64_t cbValid = 0;
3732 for (unsigned i = 0; i < RT_ELEMENTS(aBdl); i++)
3733 {
3734 aBdl[i].addr = RT_LE2H_U32(aBdl[i].addr);
3735 aBdl[i].ctl_len = RT_LE2H_U32(aBdl[i].ctl_len);
3736
3737 bool const fValid = bCiv <= bLvi
3738 ? i >= bCiv && i <= bLvi
3739 : i >= bCiv || i <= bLvi;
3740
3741 uint32_t const cb = (aBdl[i].ctl_len & AC97_BD_LEN_MASK) * PDMAudioPropsSampleSize(&Props); /** @todo or frame size? OSDev says frame... */
3742 cbTotal += cb;
3743 if (fValid)
3744 cbValid += cb;
3745
3746 char szFlags[64];
3747 szFlags[0] = '\0';
3748 if (aBdl[i].ctl_len & ~(AC97_BD_LEN_MASK | AC97_BD_IOC | AC97_BD_BUP))
3749 RTStrPrintf(szFlags, sizeof(szFlags), " !!fFlags=%#x!!\n", aBdl[i].ctl_len & ~AC97_BD_LEN_MASK);
3750
3751 pHlp->pfnPrintf(pHlp, "%s %cBDLE%02u: %#010RX32 L %#06x / LB %#RX32 / %RU64ms%s%s%s%s\n",
3752 pszPrefix, fValid ? ' ' : '?', i, aBdl[i].addr,
3753 aBdl[i].ctl_len & AC97_BD_LEN_MASK, cb, PDMAudioPropsBytesToMilli(&Props, cb),
3754 aBdl[i].ctl_len & AC97_BD_IOC ? " ioc" : "",
3755 aBdl[i].ctl_len & AC97_BD_BUP ? " bup" : "",
3756 szFlags, !(aBdl[i].addr & 3) ? "" : " !!Addr!!");
3757 }
3758
3759 pHlp->pfnPrintf(pHlp, "%sTotal: %#RX64 bytes (%RU64), %RU64 ms; Valid: %#RX64 bytes (%RU64), %RU64 ms\n", pszPrefix,
3760 cbTotal, cbTotal, PDMAudioPropsBytesToMilli(&Props, cbTotal),
3761 cbValid, cbValid, PDMAudioPropsBytesToMilli(&Props, cbValid) );
3762 }
3763}
3764
3765
3766/**
3767 * @callback_method_impl{FNDBGFHANDLERDEV, ac97bdl}
3768 */
3769static DECLCALLBACK(void) ichac97R3DbgInfoBDL(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3770{
3771 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3772 int idxStream = ichac97R3DbgLookupStrmIdx(pHlp, pszArgs);
3773 if (idxStream != -1)
3774 ichac97R3DbgPrintBdl(pDevIns, pThis, &pThis->aStreams[idxStream], pHlp, "");
3775 else
3776 for (idxStream = 0; idxStream < AC97_MAX_STREAMS; ++idxStream)
3777 ichac97R3DbgPrintBdl(pDevIns, pThis, &pThis->aStreams[idxStream], pHlp, "");
3778}
3779
3780
3781/** Worker for ichac97R3DbgInfoStream. */
3782static void ichac97R3DbgPrintStream(PCDBGFINFOHLP pHlp, PAC97STREAM pStream, PAC97STREAMR3 pStreamR3)
3783{
3784 char szTmp[PDMAUDIOSTRMCFGTOSTRING_MAX];
3785 pHlp->pfnPrintf(pHlp, "Stream #%d: %s\n", pStream->u8SD,
3786 PDMAudioStrmCfgToString(&pStreamR3->State.Cfg, szTmp, sizeof(szTmp)));
3787 pHlp->pfnPrintf(pHlp, " BDBAR %#010RX32\n", pStream->Regs.bdbar);
3788 pHlp->pfnPrintf(pHlp, " CIV %#04RX8\n", pStream->Regs.civ);
3789 pHlp->pfnPrintf(pHlp, " LVI %#04RX8\n", pStream->Regs.lvi);
3790 pHlp->pfnPrintf(pHlp, " SR %#06RX16\n", pStream->Regs.sr);
3791 pHlp->pfnPrintf(pHlp, " PICB %#06RX16\n", pStream->Regs.picb);
3792 pHlp->pfnPrintf(pHlp, " PIV %#04RX8\n", pStream->Regs.piv);
3793 pHlp->pfnPrintf(pHlp, " CR %#04RX8\n", pStream->Regs.cr);
3794 if (pStream->Regs.bd_valid)
3795 {
3796 pHlp->pfnPrintf(pHlp, " BD.ADDR %#010RX32\n", pStream->Regs.bd.addr);
3797 pHlp->pfnPrintf(pHlp, " BD.LEN %#04RX16\n", (uint16_t)pStream->Regs.bd.ctl_len);
3798 pHlp->pfnPrintf(pHlp, " BD.CTL %#04RX16\n", (uint16_t)(pStream->Regs.bd.ctl_len >> 16));
3799 }
3800
3801 pHlp->pfnPrintf(pHlp, " offRead %#RX64\n", pStreamR3->State.offRead);
3802 pHlp->pfnPrintf(pHlp, " offWrite %#RX64\n", pStreamR3->State.offWrite);
3803 pHlp->pfnPrintf(pHlp, " uTimerHz %RU16\n", pStreamR3->State.uTimerHz);
3804 pHlp->pfnPrintf(pHlp, " cTransferTicks %RU64\n", pStreamR3->State.cTransferTicks);
3805 pHlp->pfnPrintf(pHlp, " cbTransferChunk %#RX32\n", pStreamR3->State.cbTransferChunk);
3806}
3807
3808
3809/**
3810 * @callback_method_impl{FNDBGFHANDLERDEV, ac97stream}
3811 */
3812static DECLCALLBACK(void) ichac97R3DbgInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3813{
3814 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3815 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
3816 int idxStream = ichac97R3DbgLookupStrmIdx(pHlp, pszArgs);
3817 if (idxStream != -1)
3818 ichac97R3DbgPrintStream(pHlp, &pThis->aStreams[idxStream], &pThisCC->aStreams[idxStream]);
3819 else
3820 for (idxStream = 0; idxStream < AC97_MAX_STREAMS; ++idxStream)
3821 ichac97R3DbgPrintStream(pHlp, &pThis->aStreams[idxStream], &pThisCC->aStreams[idxStream]);
3822}
3823
3824
3825/*********************************************************************************************************************************
3826* PDMIBASE *
3827*********************************************************************************************************************************/
3828
3829/**
3830 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
3831 */
3832static DECLCALLBACK(void *) ichac97R3QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
3833{
3834 PAC97STATER3 pThisCC = RT_FROM_MEMBER(pInterface, AC97STATER3, IBase);
3835 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
3836 return NULL;
3837}
3838
3839
3840/*********************************************************************************************************************************
3841* PDMDEVREG *
3842*********************************************************************************************************************************/
3843
3844/**
3845 * Destroys all AC'97 audio streams of the device.
3846 *
3847 * @param pDevIns The device AC'97 instance.
3848 * @param pThis The shared AC'97 state.
3849 * @param pThisCC The ring-3 AC'97 state.
3850 */
3851static void ichac97R3StreamsDestroy(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC)
3852{
3853 LogFlowFuncEnter();
3854
3855 /*
3856 * Destroy all AC'97 streams.
3857 */
3858 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
3859 ichac97R3StreamDestroy(pThisCC, &pThis->aStreams[i], &pThisCC->aStreams[i]);
3860
3861 /*
3862 * Destroy all sinks.
3863 */
3864 if (pThisCC->pSinkLineIn)
3865 {
3866 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pThisCC->pSinkLineIn, PDMAUDIODIR_IN, PDMAUDIOPATH_IN_LINE);
3867
3868 AudioMixerSinkDestroy(pThisCC->pSinkLineIn, pDevIns);
3869 pThisCC->pSinkLineIn = NULL;
3870 }
3871
3872 if (pThisCC->pSinkMicIn)
3873 {
3874 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pThisCC->pSinkMicIn, PDMAUDIODIR_IN, PDMAUDIOPATH_IN_MIC);
3875
3876 AudioMixerSinkDestroy(pThisCC->pSinkMicIn, pDevIns);
3877 pThisCC->pSinkMicIn = NULL;
3878 }
3879
3880 if (pThisCC->pSinkOut)
3881 {
3882 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pThisCC->pSinkOut, PDMAUDIODIR_OUT, PDMAUDIOPATH_OUT_FRONT);
3883
3884 AudioMixerSinkDestroy(pThisCC->pSinkOut, pDevIns);
3885 pThisCC->pSinkOut = NULL;
3886 }
3887}
3888
3889
3890/**
3891 * Powers off the device.
3892 *
3893 * @param pDevIns Device instance to power off.
3894 */
3895static DECLCALLBACK(void) ichac97R3PowerOff(PPDMDEVINS pDevIns)
3896{
3897 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3898 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
3899
3900 LogRel2(("AC97: Powering off ...\n"));
3901
3902 /* Note: Involves mixer stream / sink destruction, so also do this here
3903 * instead of in ichac97R3Destruct(). */
3904 ichac97R3StreamsDestroy(pDevIns, pThis, pThisCC);
3905
3906 /*
3907 * Note: Destroy the mixer while powering off and *not* in ichac97R3Destruct,
3908 * giving the mixer the chance to release any references held to
3909 * PDM audio streams it maintains.
3910 */
3911 if (pThisCC->pMixer)
3912 {
3913 AudioMixerDestroy(pThisCC->pMixer, pDevIns);
3914 pThisCC->pMixer = NULL;
3915 }
3916}
3917
3918
3919/**
3920 * @interface_method_impl{PDMDEVREG,pfnReset}
3921 *
3922 * @remarks The original sources didn't install a reset handler, but it seems to
3923 * make sense to me so we'll do it.
3924 */
3925static DECLCALLBACK(void) ichac97R3Reset(PPDMDEVINS pDevIns)
3926{
3927 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3928 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
3929
3930 LogRel(("AC97: Reset\n"));
3931
3932 /*
3933 * Reset the mixer too. The Windows XP driver seems to rely on
3934 * this. At least it wants to read the vendor id before it resets
3935 * the codec manually.
3936 */
3937 ichac97R3MixerReset(pThis, pThisCC);
3938
3939 /*
3940 * Reset all streams.
3941 */
3942 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
3943 {
3944 ichac97R3StreamEnable(pDevIns, pThis, pThisCC, &pThis->aStreams[i], &pThisCC->aStreams[i], false /* fEnable */);
3945 ichac97R3StreamReset(pThis, &pThis->aStreams[i], &pThisCC->aStreams[i]);
3946 }
3947
3948 /*
3949 * Reset mixer sinks.
3950 *
3951 * Do the reset here instead of in ichac97R3StreamReset();
3952 * the mixer sink(s) might still have data to be processed when an audio stream gets reset.
3953 */
3954 AudioMixerSinkReset(pThisCC->pSinkLineIn);
3955 AudioMixerSinkReset(pThisCC->pSinkMicIn);
3956 AudioMixerSinkReset(pThisCC->pSinkOut);
3957}
3958
3959
3960/**
3961 * Adds a specific AC'97 driver to the driver chain.
3962 *
3963 * Only called from ichac97R3Attach().
3964 *
3965 * @returns VBox status code.
3966 * @param pDevIns The device instance.
3967 * @param pThisCC The ring-3 AC'97 device state.
3968 * @param pDrv The AC'97 driver to add.
3969 */
3970static int ichac97R3MixerAddDrv(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, PAC97DRIVER pDrv)
3971{
3972 int rc = VINF_SUCCESS;
3973
3974 if (AudioHlpStreamCfgIsValid(&pThisCC->aStreams[AC97SOUNDSOURCE_PI_INDEX].State.Cfg))
3975 rc = ichac97R3MixerAddDrvStream(pDevIns, pThisCC->pSinkLineIn,
3976 &pThisCC->aStreams[AC97SOUNDSOURCE_PI_INDEX].State.Cfg, pDrv);
3977
3978 if (AudioHlpStreamCfgIsValid(&pThisCC->aStreams[AC97SOUNDSOURCE_PO_INDEX].State.Cfg))
3979 {
3980 int rc2 = ichac97R3MixerAddDrvStream(pDevIns, pThisCC->pSinkOut,
3981 &pThisCC->aStreams[AC97SOUNDSOURCE_PO_INDEX].State.Cfg, pDrv);
3982 if (RT_SUCCESS(rc))
3983 rc = rc2;
3984 }
3985
3986 if (AudioHlpStreamCfgIsValid(&pThisCC->aStreams[AC97SOUNDSOURCE_MC_INDEX].State.Cfg))
3987 {
3988 int rc2 = ichac97R3MixerAddDrvStream(pDevIns, pThisCC->pSinkMicIn,
3989 &pThisCC->aStreams[AC97SOUNDSOURCE_MC_INDEX].State.Cfg, pDrv);
3990 if (RT_SUCCESS(rc))
3991 rc = rc2;
3992 }
3993
3994 return rc;
3995}
3996
3997
3998/**
3999 * Worker for ichac97R3Construct() and ichac97R3Attach().
4000 *
4001 * @returns VBox status code.
4002 * @param pDevIns The device instance.
4003 * @param pThisCC The ring-3 AC'97 device state.
4004 * @param iLun The logical unit which is being attached.
4005 * @param ppDrv Attached driver instance on success. Optional.
4006 */
4007static int ichac97R3AttachInternal(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, unsigned iLun, PAC97DRIVER *ppDrv)
4008{
4009 /*
4010 * Attach driver.
4011 */
4012 char *pszDesc = RTStrAPrintf2("Audio driver port (AC'97) for LUN #%u", iLun);
4013 AssertLogRelReturn(pszDesc, VERR_NO_STR_MEMORY);
4014
4015 PPDMIBASE pDrvBase;
4016 int rc = PDMDevHlpDriverAttach(pDevIns, iLun, &pThisCC->IBase, &pDrvBase, pszDesc);
4017 if (RT_SUCCESS(rc))
4018 {
4019 PAC97DRIVER pDrv = (PAC97DRIVER)RTMemAllocZ(sizeof(AC97DRIVER));
4020 if (pDrv)
4021 {
4022 pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
4023 AssertPtr(pDrv->pConnector);
4024 if (RT_VALID_PTR(pDrv->pConnector))
4025 {
4026 pDrv->pDrvBase = pDrvBase;
4027 pDrv->uLUN = iLun;
4028 pDrv->pszDesc = pszDesc;
4029
4030 /* Attach to driver list if not attached yet. */
4031 if (!pDrv->fAttached)
4032 {
4033 RTListAppend(&pThisCC->lstDrv, &pDrv->Node);
4034 pDrv->fAttached = true;
4035 }
4036
4037 if (ppDrv)
4038 *ppDrv = pDrv;
4039 LogFunc(("LUN#%u: returns VINF_SUCCESS (pCon=%p)\n", iLun, pDrv->pConnector));
4040 return VINF_SUCCESS;
4041 }
4042 RTMemFree(pDrv);
4043 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
4044 }
4045 else
4046 rc = VERR_NO_MEMORY;
4047 }
4048 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4049 LogFunc(("No attached driver for LUN #%u\n", iLun));
4050 else
4051 LogFunc(("Attached driver for LUN #%u failed: %Rrc\n", iLun, rc));
4052
4053 RTStrFree(pszDesc);
4054 LogFunc(("LUN#%u: rc=%Rrc\n", iLun, rc));
4055 return rc;
4056}
4057
4058
4059/**
4060 * @interface_method_impl{PDMDEVREGR3,pfnAttach}
4061 */
4062static DECLCALLBACK(int) ichac97R3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4063{
4064 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
4065 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
4066 RT_NOREF(fFlags);
4067 LogFunc(("iLUN=%u, fFlags=%#x\n", iLUN, fFlags));
4068
4069 DEVAC97_LOCK(pDevIns, pThis);
4070
4071 PAC97DRIVER pDrv;
4072 int rc = ichac97R3AttachInternal(pDevIns, pThisCC, iLUN, &pDrv);
4073 if (RT_SUCCESS(rc))
4074 {
4075 int rc2 = ichac97R3MixerAddDrv(pDevIns, pThisCC, pDrv);
4076 if (RT_FAILURE(rc2))
4077 LogFunc(("ichac97R3MixerAddDrv failed with %Rrc (ignored)\n", rc2));
4078 }
4079
4080 DEVAC97_UNLOCK(pDevIns, pThis);
4081
4082 return rc;
4083}
4084
4085
4086/**
4087 * Removes a specific AC'97 driver from the driver chain and destroys its
4088 * associated streams.
4089 *
4090 * Only called from ichac97R3Detach().
4091 *
4092 * @param pDevIns The device instance.
4093 * @param pThisCC The ring-3 AC'97 device state.
4094 * @param pDrv AC'97 driver to remove.
4095 */
4096static void ichac97R3MixerRemoveDrv(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, PAC97DRIVER pDrv)
4097{
4098 if (pDrv->MicIn.pMixStrm)
4099 {
4100 AudioMixerSinkRemoveStream(pThisCC->pSinkMicIn, pDrv->MicIn.pMixStrm);
4101 AudioMixerStreamDestroy(pDrv->MicIn.pMixStrm, pDevIns, true /*fImmediate*/);
4102 pDrv->MicIn.pMixStrm = NULL;
4103 }
4104
4105 if (pDrv->LineIn.pMixStrm)
4106 {
4107 AudioMixerSinkRemoveStream(pThisCC->pSinkLineIn, pDrv->LineIn.pMixStrm);
4108 AudioMixerStreamDestroy(pDrv->LineIn.pMixStrm, pDevIns, true /*fImmediate*/);
4109 pDrv->LineIn.pMixStrm = NULL;
4110 }
4111
4112 if (pDrv->Out.pMixStrm)
4113 {
4114 AudioMixerSinkRemoveStream(pThisCC->pSinkOut, pDrv->Out.pMixStrm);
4115 AudioMixerStreamDestroy(pDrv->Out.pMixStrm, pDevIns, true /*fImmediate*/);
4116 pDrv->Out.pMixStrm = NULL;
4117 }
4118
4119 RTListNodeRemove(&pDrv->Node);
4120}
4121
4122
4123/**
4124 * @interface_method_impl{PDMDEVREG,pfnDetach}
4125 */
4126static DECLCALLBACK(void) ichac97R3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4127{
4128 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
4129 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
4130 RT_NOREF(fFlags);
4131
4132 LogFunc(("iLUN=%u, fFlags=0x%x\n", iLUN, fFlags));
4133
4134 DEVAC97_LOCK(pDevIns, pThis);
4135
4136 PAC97DRIVER pDrv;
4137 RTListForEach(&pThisCC->lstDrv, pDrv, AC97DRIVER, Node)
4138 {
4139 if (pDrv->uLUN == iLUN)
4140 {
4141 /* Remove the driver from our list and destory it's associated streams.
4142 This also will un-set the driver as a recording source (if associated). */
4143 ichac97R3MixerRemoveDrv(pDevIns, pThisCC, pDrv);
4144 LogFunc(("Detached LUN#%u\n", pDrv->uLUN));
4145
4146 DEVAC97_UNLOCK(pDevIns, pThis);
4147
4148 RTStrFree(pDrv->pszDesc);
4149 RTMemFree(pDrv);
4150 return;
4151 }
4152 }
4153
4154 DEVAC97_UNLOCK(pDevIns, pThis);
4155 LogFunc(("LUN#%u was not found\n", iLUN));
4156}
4157
4158
4159/**
4160 * @interface_method_impl{PDMDEVREG,pfnDestruct}
4161 */
4162static DECLCALLBACK(int) ichac97R3Destruct(PPDMDEVINS pDevIns)
4163{
4164 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); /* this shall come first */
4165 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
4166
4167 LogFlowFuncEnter();
4168
4169 PAC97DRIVER pDrv, pDrvNext;
4170 RTListForEachSafe(&pThisCC->lstDrv, pDrv, pDrvNext, AC97DRIVER, Node)
4171 {
4172 RTListNodeRemove(&pDrv->Node);
4173 RTMemFree(pDrv->pszDesc);
4174 RTMemFree(pDrv);
4175 }
4176
4177 /* Sanity. */
4178 Assert(RTListIsEmpty(&pThisCC->lstDrv));
4179
4180 /* We don't always go via PowerOff, so make sure the mixer is destroyed. */
4181 if (pThisCC->pMixer)
4182 {
4183 AudioMixerDestroy(pThisCC->pMixer, pDevIns);
4184 pThisCC->pMixer = NULL;
4185 }
4186
4187 return VINF_SUCCESS;
4188}
4189
4190
4191/**
4192 * @interface_method_impl{PDMDEVREG,pfnConstruct}
4193 */
4194static DECLCALLBACK(int) ichac97R3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
4195{
4196 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* this shall come first */
4197 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
4198 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
4199 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4200 Assert(iInstance == 0); RT_NOREF(iInstance);
4201
4202 /*
4203 * Initialize data so we can run the destructor without scewing up.
4204 */
4205 pThisCC->pDevIns = pDevIns;
4206 pThisCC->IBase.pfnQueryInterface = ichac97R3QueryInterface;
4207 RTListInit(&pThisCC->lstDrv);
4208
4209 /*
4210 * Validate and read configuration.
4211 */
4212 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "BufSizeInMs|BufSizeOutMs|Codec|TimerHz|DebugEnabled|DebugPathOut", "");
4213
4214 /** @devcfgm{ac97,BufSizeInMs,uint16_t,0,2000,0,ms}
4215 * The size of the DMA buffer for input streams expressed in milliseconds. */
4216 int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeInMs", &pThis->cMsCircBufIn, 0);
4217 if (RT_FAILURE(rc))
4218 return PDMDEV_SET_ERROR(pDevIns, rc,
4219 N_("AC97 configuration error: failed to read 'BufSizeInMs' as 16-bit unsigned integer"));
4220 if (pThis->cMsCircBufIn > 2000)
4221 return PDMDEV_SET_ERROR(pDevIns, VERR_OUT_OF_RANGE,
4222 N_("AC97 configuration error: 'BufSizeInMs' is out of bound, max 2000 ms"));
4223
4224 /** @devcfgm{ac97,BufSizeOutMs,uint16_t,0,2000,0,ms}
4225 * The size of the DMA buffer for output streams expressed in milliseconds. */
4226 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeOutMs", &pThis->cMsCircBufOut, 0);
4227 if (RT_FAILURE(rc))
4228 return PDMDEV_SET_ERROR(pDevIns, rc,
4229 N_("AC97 configuration error: failed to read 'BufSizeOutMs' as 16-bit unsigned integer"));
4230 if (pThis->cMsCircBufOut > 2000)
4231 return PDMDEV_SET_ERROR(pDevIns, VERR_OUT_OF_RANGE,
4232 N_("AC97 configuration error: 'BufSizeOutMs' is out of bound, max 2000 ms"));
4233
4234 /** @devcfgm{ac97,TimerHz,uint16_t,10,1000,100,ms}
4235 * Currently the approximate rate at which the asynchronous I/O threads move
4236 * data from/to the DMA buffer, thru the mixer and drivers stack, and
4237 * to/from the host device/whatever. (It does NOT govern any DMA timer rate any
4238 * more as might be hinted at by the name.) */
4239 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "TimerHz", &pThis->uTimerHz, AC97_TIMER_HZ_DEFAULT);
4240 if (RT_FAILURE(rc))
4241 return PDMDEV_SET_ERROR(pDevIns, rc,
4242 N_("AC'97 configuration error: failed to read 'TimerHz' as a 16-bit unsigned integer"));
4243 if (pThis->uTimerHz < 10 || pThis->uTimerHz > 1000)
4244 return PDMDEV_SET_ERROR(pDevIns, VERR_OUT_OF_RANGE,
4245 N_("AC'97 configuration error: 'TimerHz' is out of range (10-1000 Hz)"));
4246
4247 if (pThis->uTimerHz != AC97_TIMER_HZ_DEFAULT)
4248 LogRel(("AC97: Using custom device timer rate: %RU16 Hz\n", pThis->uTimerHz));
4249
4250 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DebugEnabled", &pThisCC->Dbg.fEnabled, false);
4251 if (RT_FAILURE(rc))
4252 return PDMDEV_SET_ERROR(pDevIns, rc,
4253 N_("AC97 configuration error: failed to read debugging enabled flag as boolean"));
4254
4255 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "DebugPathOut", &pThisCC->Dbg.pszOutPath, NULL);
4256 if (RT_FAILURE(rc))
4257 return PDMDEV_SET_ERROR(pDevIns, rc,
4258 N_("AC97 configuration error: failed to read debugging output path flag as string"));
4259
4260 if (pThisCC->Dbg.fEnabled)
4261 LogRel2(("AC97: Debug output will be saved to '%s'\n", pThisCC->Dbg.pszOutPath));
4262
4263 /*
4264 * The AD1980 codec (with corresponding PCI subsystem vendor ID) is whitelisted
4265 * in the Linux kernel; Linux makes no attempt to measure the data rate and assumes
4266 * 48 kHz rate, which is exactly what we need. Same goes for AD1981B.
4267 */
4268 char szCodec[20];
4269 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "Codec", &szCodec[0], sizeof(szCodec), "STAC9700");
4270 if (RT_FAILURE(rc))
4271 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
4272 N_("AC'97 configuration error: Querying \"Codec\" as string failed"));
4273 if (!strcmp(szCodec, "STAC9700"))
4274 pThis->enmCodecModel = AC97CODEC_STAC9700;
4275 else if (!strcmp(szCodec, "AD1980"))
4276 pThis->enmCodecModel = AC97CODEC_AD1980;
4277 else if (!strcmp(szCodec, "AD1981B"))
4278 pThis->enmCodecModel = AC97CODEC_AD1981B;
4279 else
4280 return PDMDevHlpVMSetError(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, RT_SRC_POS,
4281 N_("AC'97 configuration error: The \"Codec\" value \"%s\" is unsupported"), szCodec);
4282
4283 LogRel(("AC97: Using codec '%s'\n", szCodec));
4284
4285 /*
4286 * Use an own critical section for the device instead of the default
4287 * one provided by PDM. This allows fine-grained locking in combination
4288 * with TM when timer-specific stuff is being called in e.g. the MMIO handlers.
4289 */
4290 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "AC'97");
4291 AssertRCReturn(rc, rc);
4292
4293 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
4294 AssertRCReturn(rc, rc);
4295
4296 /*
4297 * Initialize data (most of it anyway).
4298 */
4299 /* PCI Device */
4300 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
4301 PCIDevSetVendorId(pPciDev, 0x8086); /* 00 ro - intel. */ Assert(pPciDev->abConfig[0x00] == 0x86); Assert(pPciDev->abConfig[0x01] == 0x80);
4302 PCIDevSetDeviceId(pPciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */ Assert(pPciDev->abConfig[0x02] == 0x15); Assert(pPciDev->abConfig[0x03] == 0x24);
4303 PCIDevSetCommand(pPciDev, 0x0000); /* 04 rw,ro - pcicmd. */ Assert(pPciDev->abConfig[0x04] == 0x00); Assert(pPciDev->abConfig[0x05] == 0x00);
4304 PCIDevSetStatus(pPciDev, VBOX_PCI_STATUS_DEVSEL_MEDIUM | VBOX_PCI_STATUS_FAST_BACK); /* 06 rwc?,ro? - pcists. */ Assert(pPciDev->abConfig[0x06] == 0x80); Assert(pPciDev->abConfig[0x07] == 0x02);
4305 PCIDevSetRevisionId(pPciDev, 0x01); /* 08 ro - rid. */ Assert(pPciDev->abConfig[0x08] == 0x01);
4306 PCIDevSetClassProg(pPciDev, 0x00); /* 09 ro - pi. */ Assert(pPciDev->abConfig[0x09] == 0x00);
4307 PCIDevSetClassSub(pPciDev, 0x01); /* 0a ro - scc; 01 == Audio. */ Assert(pPciDev->abConfig[0x0a] == 0x01);
4308 PCIDevSetClassBase(pPciDev, 0x04); /* 0b ro - bcc; 04 == multimedia.*/Assert(pPciDev->abConfig[0x0b] == 0x04);
4309 PCIDevSetHeaderType(pPciDev, 0x00); /* 0e ro - headtyp. */ Assert(pPciDev->abConfig[0x0e] == 0x00);
4310 PCIDevSetBaseAddress(pPciDev, 0, /* 10 rw - nambar - native audio mixer base. */
4311 true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pPciDev->abConfig[0x10] == 0x01); Assert(pPciDev->abConfig[0x11] == 0x00); Assert(pPciDev->abConfig[0x12] == 0x00); Assert(pPciDev->abConfig[0x13] == 0x00);
4312 PCIDevSetBaseAddress(pPciDev, 1, /* 14 rw - nabmbar - native audio bus mastering. */
4313 true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pPciDev->abConfig[0x14] == 0x01); Assert(pPciDev->abConfig[0x15] == 0x00); Assert(pPciDev->abConfig[0x16] == 0x00); Assert(pPciDev->abConfig[0x17] == 0x00);
4314 PCIDevSetInterruptLine(pPciDev, 0x00); /* 3c rw. */ Assert(pPciDev->abConfig[0x3c] == 0x00);
4315 PCIDevSetInterruptPin(pPciDev, 0x01); /* 3d ro - INTA#. */ Assert(pPciDev->abConfig[0x3d] == 0x01);
4316
4317 if (pThis->enmCodecModel == AC97CODEC_AD1980)
4318 {
4319 PCIDevSetSubSystemVendorId(pPciDev, 0x1028); /* 2c ro - Dell.) */
4320 PCIDevSetSubSystemId(pPciDev, 0x0177); /* 2e ro. */
4321 }
4322 else if (pThis->enmCodecModel == AC97CODEC_AD1981B)
4323 {
4324 PCIDevSetSubSystemVendorId(pPciDev, 0x1028); /* 2c ro - Dell.) */
4325 PCIDevSetSubSystemId(pPciDev, 0x01ad); /* 2e ro. */
4326 }
4327 else
4328 {
4329 PCIDevSetSubSystemVendorId(pPciDev, 0x8086); /* 2c ro - Intel.) */
4330 PCIDevSetSubSystemId(pPciDev, 0x0000); /* 2e ro. */
4331 }
4332
4333 /*
4334 * Register the PCI device and associated I/O regions.
4335 */
4336 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
4337 if (RT_FAILURE(rc))
4338 return rc;
4339
4340 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, 0 /*iPciRegion*/, 256 /*cPorts*/,
4341 ichac97IoPortNamWrite, ichac97IoPortNamRead, NULL /*pvUser*/,
4342 "ICHAC97 NAM", NULL /*paExtDescs*/, &pThis->hIoPortsNam);
4343 AssertRCReturn(rc, rc);
4344
4345 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, 1 /*iPciRegion*/, 64 /*cPorts*/,
4346 ichac97IoPortNabmWrite, ichac97IoPortNabmRead, NULL /*pvUser*/,
4347 "ICHAC97 NABM", g_aNabmPorts, &pThis->hIoPortsNabm);
4348 AssertRCReturn(rc, rc);
4349
4350 /*
4351 * Saved state.
4352 */
4353 rc = PDMDevHlpSSMRegister(pDevIns, AC97_SAVED_STATE_VERSION, sizeof(*pThis), ichac97R3SaveExec, ichac97R3LoadExec);
4354 if (RT_FAILURE(rc))
4355 return rc;
4356
4357 /*
4358 * Attach drivers. We ASSUME they are configured consecutively without any
4359 * gaps, so we stop when we hit the first LUN w/o a driver configured.
4360 */
4361 for (unsigned iLun = 0; ; iLun++)
4362 {
4363 AssertBreak(iLun < UINT8_MAX);
4364 LogFunc(("Trying to attach driver for LUN#%u ...\n", iLun));
4365 rc = ichac97R3AttachInternal(pDevIns, pThisCC, iLun, NULL /* ppDrv */);
4366 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4367 {
4368 LogFunc(("cLUNs=%u\n", iLun));
4369 break;
4370 }
4371 AssertLogRelMsgReturn(RT_SUCCESS(rc), ("LUN#%u: rc=%Rrc\n", iLun, rc), rc);
4372 }
4373
4374 uint32_t fMixer = AUDMIXER_FLAGS_NONE;
4375 if (pThisCC->Dbg.fEnabled)
4376 fMixer |= AUDMIXER_FLAGS_DEBUG;
4377
4378 rc = AudioMixerCreate("AC'97 Mixer", 0 /* uFlags */, &pThisCC->pMixer);
4379 AssertRCReturn(rc, rc);
4380
4381 rc = AudioMixerCreateSink(pThisCC->pMixer, "Line In",
4382 PDMAUDIODIR_IN, pDevIns, &pThisCC->pSinkLineIn);
4383 AssertRCReturn(rc, rc);
4384 rc = AudioMixerCreateSink(pThisCC->pMixer, "Microphone In",
4385 PDMAUDIODIR_IN, pDevIns, &pThisCC->pSinkMicIn);
4386 AssertRCReturn(rc, rc);
4387 rc = AudioMixerCreateSink(pThisCC->pMixer, "PCM Output",
4388 PDMAUDIODIR_OUT, pDevIns, &pThisCC->pSinkOut);
4389 AssertRCReturn(rc, rc);
4390
4391 /*
4392 * Create all hardware streams.
4393 */
4394 AssertCompile(RT_ELEMENTS(pThis->aStreams) == AC97_MAX_STREAMS);
4395 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
4396 {
4397 rc = ichac97R3StreamConstruct(pThisCC, &pThis->aStreams[i], &pThisCC->aStreams[i], i /* SD# */);
4398 AssertRCReturn(rc, rc);
4399 }
4400
4401 /*
4402 * Create the emulation timers (one per stream).
4403 *
4404 * We must the critical section for the timers as the device has a
4405 * noop section associated with it.
4406 *
4407 * Note: Use TMCLOCK_VIRTUAL_SYNC here, as the guest's AC'97 driver
4408 * relies on exact (virtual) DMA timing and uses DMA Position Buffers
4409 * instead of the LPIB registers.
4410 */
4411 /** @todo r=bird: The need to use virtual sync is perhaps because TM
4412 * doesn't schedule regular TMCLOCK_VIRTUAL timers as accurately as it
4413 * should (VT-x preemption timer, etc). Hope to address that before
4414 * long. @bugref{9943}. */
4415 static const char * const s_apszNames[] = { "AC97 PI", "AC97 PO", "AC97 MC" };
4416 AssertCompile(RT_ELEMENTS(s_apszNames) == AC97_MAX_STREAMS);
4417 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
4418 {
4419 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, ichac97R3Timer, &pThis->aStreams[i],
4420 TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_RING0, s_apszNames[i], &pThis->aStreams[i].hTimer);
4421 AssertRCReturn(rc, rc);
4422
4423 rc = PDMDevHlpTimerSetCritSect(pDevIns, pThis->aStreams[i].hTimer, &pThis->CritSect);
4424 AssertRCReturn(rc, rc);
4425 }
4426
4427 ichac97R3Reset(pDevIns);
4428
4429 /*
4430 * Info items.
4431 */
4432 //PDMDevHlpDBGFInfoRegister(pDevIns, "ac97", "AC'97 registers. (ac97 [register case-insensitive])", ichac97R3DbgInfo);
4433 PDMDevHlpDBGFInfoRegister(pDevIns, "ac97bdl", "AC'97 buffer descriptor list (BDL). (ac97bdl [stream number])",
4434 ichac97R3DbgInfoBDL);
4435 PDMDevHlpDBGFInfoRegister(pDevIns, "ac97stream", "AC'97 stream info. (ac97stream [stream number])", ichac97R3DbgInfoStream);
4436 //PDMDevHlpDBGFInfoRegister(pDevIns, "ac97mixer", "AC'97 mixer state.", ichac97R3DbgInfoMixer);
4437
4438 /*
4439 * Register statistics.
4440 */
4441 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatUnimplementedNabmReads, STAMTYPE_COUNTER, "UnimplementedNabmReads", STAMUNIT_OCCURENCES, "Unimplemented NABM register reads.");
4442 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatUnimplementedNabmWrites, STAMTYPE_COUNTER, "UnimplementedNabmWrites", STAMUNIT_OCCURENCES, "Unimplemented NABM register writes.");
4443# ifdef VBOX_WITH_STATISTICS
4444 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer, STAMTYPE_PROFILE, "Timer", STAMUNIT_TICKS_PER_CALL, "Profiling ichac97Timer.");
4445 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn, STAMTYPE_PROFILE, "Input", STAMUNIT_TICKS_PER_CALL, "Profiling input.");
4446 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatOut, STAMTYPE_PROFILE, "Output", STAMUNIT_TICKS_PER_CALL, "Profiling output.");
4447 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, "BytesRead" , STAMUNIT_BYTES, "Bytes read from AC97 emulation.");
4448 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "BytesWritten", STAMUNIT_BYTES, "Bytes written to AC97 emulation.");
4449# endif
4450 for (unsigned idxStream = 0; idxStream < RT_ELEMENTS(pThis->aStreams); idxStream++)
4451 {
4452 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.offRead, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
4453 "Virtual internal buffer read position.", "Stream%u/offRead", idxStream);
4454 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.offWrite, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
4455 "Virtual internal buffer write position.", "Stream%u/offWrite", idxStream);
4456 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaBufSize, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
4457 "Size of the internal DMA buffer.", "Stream%u/DMABufSize", idxStream);
4458 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaBufUsed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
4459 "Number of bytes used in the internal DMA buffer.", "Stream%u/DMABufUsed", idxStream);
4460 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowProblems, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
4461 "Number of internal DMA buffer problems.", "Stream%u/DMABufferProblems", idxStream);
4462 if (ichac97R3GetDirFromSD(idxStream) == PDMAUDIODIR_OUT)
4463 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
4464 "Number of internal DMA buffer overflows.", "Stream%u/DMABufferOverflows", idxStream);
4465 else
4466 {
4467 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
4468 "Number of internal DMA buffer underuns.", "Stream%u/DMABufferUnderruns", idxStream);
4469 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrorBytes, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
4470 "Number of bytes of silence added to cope with underruns.", "Stream%u/DMABufferSilence", idxStream);
4471 }
4472 }
4473
4474 LogFlowFuncLeaveRC(VINF_SUCCESS);
4475 return VINF_SUCCESS;
4476}
4477
4478#else /* !IN_RING3 */
4479
4480/**
4481 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
4482 */
4483static DECLCALLBACK(int) ichac97RZConstruct(PPDMDEVINS pDevIns)
4484{
4485 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
4486 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
4487
4488 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
4489 AssertRCReturn(rc, rc);
4490
4491 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsNam, ichac97IoPortNamWrite, ichac97IoPortNamRead, NULL /*pvUser*/);
4492 AssertRCReturn(rc, rc);
4493 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsNabm, ichac97IoPortNabmWrite, ichac97IoPortNabmRead, NULL /*pvUser*/);
4494 AssertRCReturn(rc, rc);
4495
4496 return VINF_SUCCESS;
4497}
4498
4499#endif /* !IN_RING3 */
4500
4501/**
4502 * The device registration structure.
4503 */
4504const PDMDEVREG g_DeviceICHAC97 =
4505{
4506 /* .u32Version = */ PDM_DEVREG_VERSION,
4507 /* .uReserved0 = */ 0,
4508 /* .szName = */ "ichac97",
4509 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
4510 | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION /* stream clearnup with working drivers */,
4511 /* .fClass = */ PDM_DEVREG_CLASS_AUDIO,
4512 /* .cMaxInstances = */ 1,
4513 /* .uSharedVersion = */ 42,
4514 /* .cbInstanceShared = */ sizeof(AC97STATE),
4515 /* .cbInstanceCC = */ CTX_EXPR(sizeof(AC97STATER3), 0, 0),
4516 /* .cbInstanceRC = */ 0,
4517 /* .cMaxPciDevices = */ 1,
4518 /* .cMaxMsixVectors = */ 0,
4519 /* .pszDescription = */ "ICH AC'97 Audio Controller",
4520#if defined(IN_RING3)
4521 /* .pszRCMod = */ "VBoxDDRC.rc",
4522 /* .pszR0Mod = */ "VBoxDDR0.r0",
4523 /* .pfnConstruct = */ ichac97R3Construct,
4524 /* .pfnDestruct = */ ichac97R3Destruct,
4525 /* .pfnRelocate = */ NULL,
4526 /* .pfnMemSetup = */ NULL,
4527 /* .pfnPowerOn = */ NULL,
4528 /* .pfnReset = */ ichac97R3Reset,
4529 /* .pfnSuspend = */ NULL,
4530 /* .pfnResume = */ NULL,
4531 /* .pfnAttach = */ ichac97R3Attach,
4532 /* .pfnDetach = */ ichac97R3Detach,
4533 /* .pfnQueryInterface = */ NULL,
4534 /* .pfnInitComplete = */ NULL,
4535 /* .pfnPowerOff = */ ichac97R3PowerOff,
4536 /* .pfnSoftReset = */ NULL,
4537 /* .pfnReserved0 = */ NULL,
4538 /* .pfnReserved1 = */ NULL,
4539 /* .pfnReserved2 = */ NULL,
4540 /* .pfnReserved3 = */ NULL,
4541 /* .pfnReserved4 = */ NULL,
4542 /* .pfnReserved5 = */ NULL,
4543 /* .pfnReserved6 = */ NULL,
4544 /* .pfnReserved7 = */ NULL,
4545#elif defined(IN_RING0)
4546 /* .pfnEarlyConstruct = */ NULL,
4547 /* .pfnConstruct = */ ichac97RZConstruct,
4548 /* .pfnDestruct = */ NULL,
4549 /* .pfnFinalDestruct = */ NULL,
4550 /* .pfnRequest = */ NULL,
4551 /* .pfnReserved0 = */ NULL,
4552 /* .pfnReserved1 = */ NULL,
4553 /* .pfnReserved2 = */ NULL,
4554 /* .pfnReserved3 = */ NULL,
4555 /* .pfnReserved4 = */ NULL,
4556 /* .pfnReserved5 = */ NULL,
4557 /* .pfnReserved6 = */ NULL,
4558 /* .pfnReserved7 = */ NULL,
4559#elif defined(IN_RC)
4560 /* .pfnConstruct = */ ichac97RZConstruct,
4561 /* .pfnReserved0 = */ NULL,
4562 /* .pfnReserved1 = */ NULL,
4563 /* .pfnReserved2 = */ NULL,
4564 /* .pfnReserved3 = */ NULL,
4565 /* .pfnReserved4 = */ NULL,
4566 /* .pfnReserved5 = */ NULL,
4567 /* .pfnReserved6 = */ NULL,
4568 /* .pfnReserved7 = */ NULL,
4569#else
4570# error "Not in IN_RING3, IN_RING0 or IN_RC!"
4571#endif
4572 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
4573};
4574
4575#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
4576
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette