VirtualBox

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

Last change on this file since 89759 was 89759, checked in by vboxsync, 3 years ago

DevIchAc97: Logging fix. bugref:9890

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

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