VirtualBox

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

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

Audio: Made PDMAUDIOVOLUME multichannel. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 191.4 KB
Line 
1/* $Id: DevIchAc97.cpp 89768 2021-06-17 23:03:19Z 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 LogFunc(("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 LogFunc(("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 Log3Func(("Pre-buffering (got %#x out of %#x bytes)...\n", cbStreamUsed, cbPreBuffer));
1359 fWriteSilence = true;
1360 cbStreamUsed = cbPeriod;
1361 }
1362 else
1363 {
1364 Log3Func(("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 LogFunc(("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 LogFunc(("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;
3037 PDMAudioVolumeInitFromStereo(&Vol, fCtlMuted, lVol, rVol);
3038
3039 PAUDMIXSINK pSink = NULL;
3040 switch (enmMixerCtl)
3041 {
3042 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
3043 rc = AudioMixerSetMasterVolume(pThisCC->pMixer, &Vol);
3044 break;
3045
3046 case PDMAUDIOMIXERCTL_FRONT:
3047 pSink = pThisCC->pSinkOut;
3048 break;
3049
3050 case PDMAUDIOMIXERCTL_MIC_IN:
3051 case PDMAUDIOMIXERCTL_LINE_IN:
3052 /* These are recognized but do nothing. */
3053 break;
3054
3055 default:
3056 AssertFailed();
3057 rc = VERR_NOT_SUPPORTED;
3058 break;
3059 }
3060
3061 if (pSink)
3062 rc = AudioMixerSinkSetVolume(pSink, &Vol);
3063 }
3064
3065 ichac97MixerSet(pThis, index, uVal);
3066
3067 if (RT_FAILURE(rc))
3068 LogFlowFunc(("Failed with %Rrc\n", rc));
3069
3070 return rc;
3071}
3072
3073/**
3074 * Sets the gain of a specific AC'97 recording control.
3075 *
3076 * @note Gain support is currently not implemented in PDM audio.
3077 *
3078 * @returns VBox status code.
3079 * @param pThis The shared AC'97 state.
3080 * @param pThisCC The ring-3 AC'97 state.
3081 * @param index AC'97 mixer index to set volume for.
3082 * @param enmMixerCtl Corresponding audio mixer sink.
3083 * @param uVal Volume value to set.
3084 */
3085static int ichac97R3MixerSetGain(PAC97STATE pThis, PAC97STATER3 pThisCC, int index, PDMAUDIOMIXERCTL enmMixerCtl, uint32_t uVal)
3086{
3087 /*
3088 * For AC'97 recording controls, each additional step means +1.5dB gain with
3089 * zero being 0dB gain and 15 being +22.5dB gain.
3090 */
3091 bool const fCtlMuted = (uVal >> AC97_BARS_VOL_MUTE_SHIFT) & 1;
3092 uint8_t uCtlGainLeft = (uVal >> 8) & AC97_BARS_GAIN_MASK;
3093 uint8_t uCtlGainRight = uVal & AC97_BARS_GAIN_MASK;
3094
3095 Assert(uCtlGainLeft <= 255 / AC97_DB_FACTOR);
3096 Assert(uCtlGainRight <= 255 / AC97_DB_FACTOR);
3097
3098 LogFunc(("index=0x%x, uVal=%RU32, enmMixerCtl=%RU32\n", index, uVal, enmMixerCtl));
3099 LogFunc(("uCtlGainLeft=%RU8, uCtlGainRight=%RU8 ", uCtlGainLeft, uCtlGainRight));
3100
3101 uint8_t lVol = PDMAUDIO_VOLUME_MAX + uCtlGainLeft * AC97_DB_FACTOR;
3102 uint8_t rVol = PDMAUDIO_VOLUME_MAX + uCtlGainRight * AC97_DB_FACTOR;
3103
3104 /* We do not currently support gain. Since AC'97 does not support attenuation
3105 * for the recording input, the best we can do is set the maximum volume.
3106 */
3107# ifndef VBOX_WITH_AC97_GAIN_SUPPORT
3108 /* NB: Currently there is no gain support, only attenuation. Since AC'97 does not
3109 * support attenuation for the recording inputs, the best we can do is set the
3110 * maximum volume.
3111 */
3112 lVol = rVol = PDMAUDIO_VOLUME_MAX;
3113# endif
3114
3115 Log(("-> fMuted=%RTbool, lVol=%RU8, rVol=%RU8\n", fCtlMuted, lVol, rVol));
3116
3117 int rc = VINF_SUCCESS;
3118
3119 if (pThisCC->pMixer) /* Device can be in reset state, so no mixer available. */
3120 {
3121 PDMAUDIOVOLUME Vol;
3122 PDMAudioVolumeInitFromStereo(&Vol, fCtlMuted, lVol, rVol);
3123
3124 PAUDMIXSINK pSink = NULL;
3125 switch (enmMixerCtl)
3126 {
3127 case PDMAUDIOMIXERCTL_MIC_IN:
3128 pSink = pThisCC->pSinkMicIn;
3129 break;
3130
3131 case PDMAUDIOMIXERCTL_LINE_IN:
3132 pSink = pThisCC->pSinkLineIn;
3133 break;
3134
3135 default:
3136 AssertFailed();
3137 rc = VERR_NOT_SUPPORTED;
3138 break;
3139 }
3140
3141 if (pSink)
3142 {
3143 rc = AudioMixerSinkSetVolume(pSink, &Vol);
3144 /* There is only one AC'97 recording gain control. If line in
3145 * is changed, also update the microphone. If the optional dedicated
3146 * microphone is changed, only change that.
3147 * NB: The codecs we support do not have the dedicated microphone control.
3148 */
3149 if (pSink == pThisCC->pSinkLineIn && pThisCC->pSinkMicIn)
3150 rc = AudioMixerSinkSetVolume(pSink, &Vol);
3151 }
3152 }
3153
3154 ichac97MixerSet(pThis, index, uVal);
3155
3156 if (RT_FAILURE(rc))
3157 LogFlowFunc(("Failed with %Rrc\n", rc));
3158
3159 return rc;
3160}
3161
3162
3163/**
3164 * Converts an AC'97 recording source index to a PDM audio recording source.
3165 *
3166 * @returns PDM audio recording source.
3167 * @param uIdx AC'97 index to convert.
3168 */
3169static PDMAUDIOPATH ichac97R3IdxToRecSource(uint8_t uIdx)
3170{
3171 switch (uIdx)
3172 {
3173 case AC97_REC_MIC: return PDMAUDIOPATH_IN_MIC;
3174 case AC97_REC_CD: return PDMAUDIOPATH_IN_CD;
3175 case AC97_REC_VIDEO: return PDMAUDIOPATH_IN_VIDEO;
3176 case AC97_REC_AUX: return PDMAUDIOPATH_IN_AUX;
3177 case AC97_REC_LINE_IN: return PDMAUDIOPATH_IN_LINE;
3178 case AC97_REC_PHONE: return PDMAUDIOPATH_IN_PHONE;
3179 default:
3180 break;
3181 }
3182
3183 LogFlowFunc(("Unknown record source %d, using MIC\n", uIdx));
3184 return PDMAUDIOPATH_IN_MIC;
3185}
3186
3187
3188/**
3189 * Converts a PDM audio recording source to an AC'97 recording source index.
3190 *
3191 * @returns AC'97 recording source index.
3192 * @param enmRecSrc PDM audio recording source to convert.
3193 */
3194static uint8_t ichac97R3RecSourceToIdx(PDMAUDIOPATH enmRecSrc)
3195{
3196 switch (enmRecSrc)
3197 {
3198 case PDMAUDIOPATH_IN_MIC: return AC97_REC_MIC;
3199 case PDMAUDIOPATH_IN_CD: return AC97_REC_CD;
3200 case PDMAUDIOPATH_IN_VIDEO: return AC97_REC_VIDEO;
3201 case PDMAUDIOPATH_IN_AUX: return AC97_REC_AUX;
3202 case PDMAUDIOPATH_IN_LINE: return AC97_REC_LINE_IN;
3203 case PDMAUDIOPATH_IN_PHONE: return AC97_REC_PHONE;
3204 default:
3205 AssertMsgFailedBreak(("%d\n", enmRecSrc));
3206 }
3207
3208 LogFlowFunc(("Unknown audio recording source %d using MIC\n", enmRecSrc));
3209 return AC97_REC_MIC;
3210}
3211
3212
3213/**
3214 * Performs an AC'97 mixer record select to switch to a different recording
3215 * source.
3216 *
3217 * @param pThis The shared AC'97 state.
3218 * @param val AC'97 recording source index to set.
3219 */
3220static void ichac97R3MixerRecordSelect(PAC97STATE pThis, uint32_t val)
3221{
3222 uint8_t rs = val & AC97_REC_MASK;
3223 uint8_t ls = (val >> 8) & AC97_REC_MASK;
3224
3225 PDMAUDIOPATH const ars = ichac97R3IdxToRecSource(rs);
3226 PDMAUDIOPATH const als = ichac97R3IdxToRecSource(ls);
3227
3228 rs = ichac97R3RecSourceToIdx(ars);
3229 ls = ichac97R3RecSourceToIdx(als);
3230
3231 LogRel(("AC97: Record select to left=%s, right=%s\n", PDMAudioPathGetName(ars), PDMAudioPathGetName(als)));
3232
3233 ichac97MixerSet(pThis, AC97_Record_Select, rs | (ls << 8));
3234}
3235
3236/**
3237 * Resets the AC'97 mixer.
3238 *
3239 * @returns VBox status code.
3240 * @param pThis The shared AC'97 state.
3241 * @param pThisCC The ring-3 AC'97 state.
3242 */
3243static int ichac97R3MixerReset(PAC97STATE pThis, PAC97STATER3 pThisCC)
3244{
3245 LogFlowFuncEnter();
3246
3247 RT_ZERO(pThis->mixer_data);
3248
3249 /* Note: Make sure to reset all registers first before bailing out on error. */
3250
3251 ichac97MixerSet(pThis, AC97_Reset , 0x0000); /* 6940 */
3252 ichac97MixerSet(pThis, AC97_Master_Volume_Mono_Mute , 0x8000);
3253 ichac97MixerSet(pThis, AC97_PC_BEEP_Volume_Mute , 0x0000);
3254
3255 ichac97MixerSet(pThis, AC97_Phone_Volume_Mute , 0x8008);
3256 ichac97MixerSet(pThis, AC97_Mic_Volume_Mute , 0x8008);
3257 ichac97MixerSet(pThis, AC97_CD_Volume_Mute , 0x8808);
3258 ichac97MixerSet(pThis, AC97_Aux_Volume_Mute , 0x8808);
3259 ichac97MixerSet(pThis, AC97_Record_Gain_Mic_Mute , 0x8000);
3260 ichac97MixerSet(pThis, AC97_General_Purpose , 0x0000);
3261 ichac97MixerSet(pThis, AC97_3D_Control , 0x0000);
3262 ichac97MixerSet(pThis, AC97_Powerdown_Ctrl_Stat , 0x000f);
3263
3264 /* Configure Extended Audio ID (EAID) + Control & Status (EACS) registers. */
3265 const uint16_t fEAID = AC97_EAID_REV1 | AC97_EACS_VRA | AC97_EACS_VRM; /* Our hardware is AC'97 rev2.3 compliant. */
3266 const uint16_t fEACS = AC97_EACS_VRA | AC97_EACS_VRM; /* Variable Rate PCM Audio (VRA) + Mic-In (VRM) capable. */
3267
3268 LogRel(("AC97: Mixer reset (EAID=0x%x, EACS=0x%x)\n", fEAID, fEACS));
3269
3270 ichac97MixerSet(pThis, AC97_Extended_Audio_ID, fEAID);
3271 ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, fEACS);
3272 ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate , 0xbb80 /* 48000 Hz by default */);
3273 ichac97MixerSet(pThis, AC97_PCM_Surround_DAC_Rate , 0xbb80 /* 48000 Hz by default */);
3274 ichac97MixerSet(pThis, AC97_PCM_LFE_DAC_Rate , 0xbb80 /* 48000 Hz by default */);
3275 ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate , 0xbb80 /* 48000 Hz by default */);
3276 ichac97MixerSet(pThis, AC97_MIC_ADC_Rate , 0xbb80 /* 48000 Hz by default */);
3277
3278 if (pThis->enmCodecModel == AC97CODEC_AD1980)
3279 {
3280 /* Analog Devices 1980 (AD1980) */
3281 ichac97MixerSet(pThis, AC97_Reset , 0x0010); /* Headphones. */
3282 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144);
3283 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5370);
3284 ichac97MixerSet(pThis, AC97_Headphone_Volume_Mute , 0x8000);
3285 }
3286 else if (pThis->enmCodecModel == AC97CODEC_AD1981B)
3287 {
3288 /* Analog Devices 1981B (AD1981B) */
3289 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144);
3290 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5374);
3291 }
3292 else
3293 {
3294 /* Sigmatel 9700 (STAC9700) */
3295 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x8384);
3296 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x7600); /* 7608 */
3297 }
3298 ichac97R3MixerRecordSelect(pThis, 0);
3299
3300 /* The default value is 8000h, which corresponds to 0 dB attenuation with mute on. */
3301 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER, 0x8000);
3302
3303 /* The default value for stereo registers is 8808h, which corresponds to 0 dB gain with mute on.*/
3304 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT, 0x8808);
3305 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808);
3306 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Mic_Volume_Mute, PDMAUDIOMIXERCTL_MIC_IN, 0x8008);
3307
3308 /* The default for record controls is 0 dB gain with mute on. */
3309 ichac97R3MixerSetGain(pThis, pThisCC, AC97_Record_Gain_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8000);
3310 ichac97R3MixerSetGain(pThis, pThisCC, AC97_Record_Gain_Mic_Mute, PDMAUDIOMIXERCTL_MIC_IN, 0x8000);
3311
3312 return VINF_SUCCESS;
3313}
3314
3315#endif /* IN_RING3 */
3316
3317/**
3318 * @callback_method_impl{FNIOMIOPORTNEWIN}
3319 */
3320static DECLCALLBACK(VBOXSTRICTRC)
3321ichac97IoPortNamRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
3322{
3323 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3324 RT_NOREF(pvUser);
3325 Assert(offPort < 256);
3326
3327 DEVAC97_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_IOPORT_READ);
3328
3329 VBOXSTRICTRC rc = VINF_SUCCESS;
3330 switch (cb)
3331 {
3332 case 1:
3333 LogRel2(("AC97: Warning: Unimplemented read (1 byte) offPort=%#x\n", offPort));
3334 pThis->cas = 0;
3335 *pu32 = UINT32_MAX;
3336 break;
3337
3338 case 2:
3339 pThis->cas = 0;
3340 *pu32 = ichac97MixerGet(pThis, offPort);
3341 break;
3342
3343 case 4:
3344 LogRel2(("AC97: Warning: Unimplemented read (4 bytes) offPort=%#x\n", offPort));
3345 pThis->cas = 0;
3346 *pu32 = UINT32_MAX;
3347 break;
3348
3349 default:
3350 AssertFailed();
3351 rc = VERR_IOM_IOPORT_UNUSED;
3352 break;
3353 }
3354
3355 DEVAC97_UNLOCK(pDevIns, pThis);
3356 return rc;
3357}
3358
3359/**
3360 * @callback_method_impl{FNIOMIOPORTNEWOUT}
3361 */
3362static DECLCALLBACK(VBOXSTRICTRC)
3363ichac97IoPortNamWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
3364{
3365 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3366#ifdef IN_RING3
3367 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
3368#endif
3369 RT_NOREF(pvUser);
3370
3371 DEVAC97_LOCK_RETURN(pDevIns, pThis, VINF_IOM_R3_IOPORT_WRITE);
3372
3373 VBOXSTRICTRC rc = VINF_SUCCESS;
3374 switch (cb)
3375 {
3376 case 1:
3377 LogRel2(("AC97: Warning: Unimplemented NAMWrite (1 byte) offPort=%#x <- %#x\n", offPort, u32));
3378 pThis->cas = 0;
3379 break;
3380
3381 case 2:
3382 {
3383 pThis->cas = 0;
3384 switch (offPort)
3385 {
3386 case AC97_Reset:
3387#ifdef IN_RING3
3388 ichac97R3Reset(pDevIns);
3389#else
3390 rc = VINF_IOM_R3_IOPORT_WRITE;
3391#endif
3392 break;
3393 case AC97_Powerdown_Ctrl_Stat:
3394 u32 &= ~0xf;
3395 u32 |= ichac97MixerGet(pThis, offPort) & 0xf;
3396 ichac97MixerSet(pThis, offPort, u32);
3397 break;
3398 case AC97_Master_Volume_Mute:
3399 if (pThis->enmCodecModel == AC97CODEC_AD1980)
3400 {
3401 if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_LOSEL)
3402 break; /* Register controls surround (rear), do nothing. */
3403 }
3404#ifdef IN_RING3
3405 ichac97R3MixerSetVolume(pThis, pThisCC, offPort, PDMAUDIOMIXERCTL_VOLUME_MASTER, u32);
3406#else
3407 rc = VINF_IOM_R3_IOPORT_WRITE;
3408#endif
3409 break;
3410 case AC97_Headphone_Volume_Mute:
3411 if (pThis->enmCodecModel == AC97CODEC_AD1980)
3412 {
3413 if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_HPSEL)
3414 {
3415 /* Register controls PCM (front) outputs. */
3416#ifdef IN_RING3
3417 ichac97R3MixerSetVolume(pThis, pThisCC, offPort, PDMAUDIOMIXERCTL_VOLUME_MASTER, u32);
3418#else
3419 rc = VINF_IOM_R3_IOPORT_WRITE;
3420#endif
3421 }
3422 }
3423 break;
3424 case AC97_PCM_Out_Volume_Mute:
3425#ifdef IN_RING3
3426 ichac97R3MixerSetVolume(pThis, pThisCC, offPort, PDMAUDIOMIXERCTL_FRONT, u32);
3427#else
3428 rc = VINF_IOM_R3_IOPORT_WRITE;
3429#endif
3430 break;
3431 case AC97_Line_In_Volume_Mute:
3432#ifdef IN_RING3
3433 ichac97R3MixerSetVolume(pThis, pThisCC, offPort, PDMAUDIOMIXERCTL_LINE_IN, u32);
3434#else
3435 rc = VINF_IOM_R3_IOPORT_WRITE;
3436#endif
3437 break;
3438 case AC97_Record_Select:
3439#ifdef IN_RING3
3440 ichac97R3MixerRecordSelect(pThis, u32);
3441#else
3442 rc = VINF_IOM_R3_IOPORT_WRITE;
3443#endif
3444 break;
3445 case AC97_Record_Gain_Mute:
3446#ifdef IN_RING3
3447 /* Newer Ubuntu guests rely on that when controlling gain and muting
3448 * the recording (capturing) levels. */
3449 ichac97R3MixerSetGain(pThis, pThisCC, offPort, PDMAUDIOMIXERCTL_LINE_IN, u32);
3450#else
3451 rc = VINF_IOM_R3_IOPORT_WRITE;
3452#endif
3453 break;
3454 case AC97_Record_Gain_Mic_Mute:
3455#ifdef IN_RING3
3456 /* Ditto; see note above. */
3457 ichac97R3MixerSetGain(pThis, pThisCC, offPort, PDMAUDIOMIXERCTL_MIC_IN, u32);
3458#else
3459 rc = VINF_IOM_R3_IOPORT_WRITE;
3460#endif
3461 break;
3462 case AC97_Vendor_ID1:
3463 case AC97_Vendor_ID2:
3464 LogFunc(("Attempt to write vendor ID to %#x\n", u32));
3465 break;
3466 case AC97_Extended_Audio_ID:
3467 LogFunc(("Attempt to write extended audio ID to %#x\n", u32));
3468 break;
3469 case AC97_Extended_Audio_Ctrl_Stat:
3470#ifdef IN_RING3
3471 /*
3472 * Handle VRA bits.
3473 */
3474 if (!(u32 & AC97_EACS_VRA)) /* Check if VRA bit is not set. */
3475 {
3476 ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate, 0xbb80); /* Set default (48000 Hz). */
3477 /** @todo r=bird: Why reopen it now? Can't we put that off till it's
3478 * actually used? */
3479 ichac97R3StreamReSetUp(pDevIns, pThis, pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX],
3480 &pThisCC->aStreams[AC97SOUNDSOURCE_PO_INDEX], true /* fForce */);
3481
3482 ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate, 0xbb80); /* Set default (48000 Hz). */
3483 /** @todo r=bird: Why reopen it now? Can't we put that off till it's
3484 * actually used? */
3485 ichac97R3StreamReSetUp(pDevIns, pThis, pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX],
3486 &pThisCC->aStreams[AC97SOUNDSOURCE_PI_INDEX], true /* fForce */);
3487 }
3488 else
3489 LogRel2(("AC97: Variable rate audio (VRA) is not supported\n"));
3490
3491 /*
3492 * Handle VRM bits.
3493 */
3494 if (!(u32 & AC97_EACS_VRM)) /* Check if VRM bit is not set. */
3495 {
3496 ichac97MixerSet(pThis, AC97_MIC_ADC_Rate, 0xbb80); /* Set default (48000 Hz). */
3497 /** @todo r=bird: Why reopen it now? Can't we put that off till it's
3498 * actually used? */
3499 ichac97R3StreamReSetUp(pDevIns, pThis, pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX],
3500 &pThisCC->aStreams[AC97SOUNDSOURCE_MC_INDEX], true /* fForce */);
3501 }
3502 else
3503 LogRel2(("AC97: Variable rate microphone audio (VRM) is not supported\n"));
3504
3505 LogRel2(("AC97: Setting extended audio control to %#x\n", u32));
3506 ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, u32);
3507#else /* !IN_RING3 */
3508 rc = VINF_IOM_R3_IOPORT_WRITE;
3509#endif
3510 break;
3511 case AC97_PCM_Front_DAC_Rate: /* Output slots 3, 4, 6. */
3512#ifdef IN_RING3
3513 if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRA)
3514 {
3515 LogRel2(("AC97: Setting front DAC rate to 0x%x\n", u32));
3516 ichac97MixerSet(pThis, offPort, u32);
3517 /** @todo r=bird: Why reopen it now? Can't we put that off till it's
3518 * actually used? */
3519 ichac97R3StreamReSetUp(pDevIns, pThis, pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX],
3520 &pThisCC->aStreams[AC97SOUNDSOURCE_PO_INDEX], true /* fForce */);
3521 }
3522 else
3523 LogRel2(("AC97: Setting front DAC rate (0x%x) when VRA is not set is forbidden, ignoring\n", u32));
3524#else
3525 rc = VINF_IOM_R3_IOPORT_WRITE;
3526#endif
3527 break;
3528 case AC97_MIC_ADC_Rate: /* Input slot 6. */
3529#ifdef IN_RING3
3530 if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRM)
3531 {
3532 LogRel2(("AC97: Setting microphone ADC rate to 0x%x\n", u32));
3533 ichac97MixerSet(pThis, offPort, u32);
3534 /** @todo r=bird: Why reopen it now? Can't we put that off till it's
3535 * actually used? */
3536 ichac97R3StreamReSetUp(pDevIns, pThis, pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX],
3537 &pThisCC->aStreams[AC97SOUNDSOURCE_MC_INDEX], true /* fForce */);
3538 }
3539 else
3540 LogRel2(("AC97: Setting microphone ADC rate (0x%x) when VRM is not set is forbidden, ignoring\n", u32));
3541#else
3542 rc = VINF_IOM_R3_IOPORT_WRITE;
3543#endif
3544 break;
3545 case AC97_PCM_LR_ADC_Rate: /* Input slots 3, 4. */
3546#ifdef IN_RING3
3547 if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRA)
3548 {
3549 LogRel2(("AC97: Setting line-in ADC rate to 0x%x\n", u32));
3550 ichac97MixerSet(pThis, offPort, u32);
3551 /** @todo r=bird: Why reopen it now? Can't we put that off till it's
3552 * actually used? */
3553 ichac97R3StreamReSetUp(pDevIns, pThis, pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX],
3554 &pThisCC->aStreams[AC97SOUNDSOURCE_PI_INDEX], true /* fForce */);
3555 }
3556 else
3557 LogRel2(("AC97: Setting line-in ADC rate (0x%x) when VRA is not set is forbidden, ignoring\n", u32));
3558#else
3559 rc = VINF_IOM_R3_IOPORT_WRITE;
3560#endif
3561 break;
3562 default:
3563 LogRel2(("AC97: Warning: Unimplemented NAMWrite (2 bytes) offPort=%#x <- %#x\n", offPort, u32));
3564 ichac97MixerSet(pThis, offPort, u32);
3565 break;
3566 }
3567 break;
3568 }
3569
3570 case 4:
3571 LogRel2(("AC97: Warning: Unimplemented 4 byte NAMWrite: offPort=%#x <- %#x\n", offPort, u32));
3572 pThis->cas = 0;
3573 break;
3574
3575 default:
3576 AssertMsgFailed(("Unhandled NAMWrite offPort=%#x, cb=%u u32=%#x\n", offPort, cb, u32));
3577 break;
3578 }
3579
3580 DEVAC97_UNLOCK(pDevIns, pThis);
3581 return rc;
3582}
3583
3584#ifdef IN_RING3
3585
3586
3587/*********************************************************************************************************************************
3588* State Saving & Loading *
3589*********************************************************************************************************************************/
3590
3591/**
3592 * Saves (serializes) an AC'97 stream using SSM.
3593 *
3594 * @param pDevIns Device instance.
3595 * @param pSSM Saved state manager (SSM) handle to use.
3596 * @param pStream AC'97 stream to save.
3597 */
3598static void ichac97R3SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStream)
3599{
3600 PAC97BMREGS pRegs = &pStream->Regs;
3601 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3602
3603 pHlp->pfnSSMPutU32(pSSM, pRegs->bdbar);
3604 pHlp->pfnSSMPutU8( pSSM, pRegs->civ);
3605 pHlp->pfnSSMPutU8( pSSM, pRegs->lvi);
3606 pHlp->pfnSSMPutU16(pSSM, pRegs->sr);
3607 pHlp->pfnSSMPutU16(pSSM, pRegs->picb);
3608 pHlp->pfnSSMPutU8( pSSM, pRegs->piv);
3609 pHlp->pfnSSMPutU8( pSSM, pRegs->cr);
3610 pHlp->pfnSSMPutS32(pSSM, pRegs->bd_valid);
3611 pHlp->pfnSSMPutU32(pSSM, pRegs->bd.addr);
3612 pHlp->pfnSSMPutU32(pSSM, pRegs->bd.ctl_len);
3613}
3614
3615
3616/**
3617 * @callback_method_impl{FNSSMDEVSAVEEXEC}
3618 */
3619static DECLCALLBACK(int) ichac97R3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
3620{
3621 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3622 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
3623 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3624 LogFlowFuncEnter();
3625
3626 pHlp->pfnSSMPutU32(pSSM, pThis->glob_cnt);
3627 pHlp->pfnSSMPutU32(pSSM, pThis->glob_sta);
3628 pHlp->pfnSSMPutU32(pSSM, pThis->cas);
3629
3630 /*
3631 * The order that the streams are saved here is fixed, so don't change.
3632 */
3633 /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
3634 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
3635 ichac97R3SaveStream(pDevIns, pSSM, &pThis->aStreams[i]);
3636
3637 pHlp->pfnSSMPutMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
3638
3639 /* The stream order is against fixed and set in stone. */
3640 uint8_t afActiveStrms[AC97SOUNDSOURCE_MAX];
3641 afActiveStrms[AC97SOUNDSOURCE_PI_INDEX] = ichac97R3StreamIsEnabled(pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX]);
3642 afActiveStrms[AC97SOUNDSOURCE_PO_INDEX] = ichac97R3StreamIsEnabled(pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX]);
3643 afActiveStrms[AC97SOUNDSOURCE_MC_INDEX] = ichac97R3StreamIsEnabled(pThisCC, &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX]);
3644 AssertCompile(RT_ELEMENTS(afActiveStrms) == 3);
3645 pHlp->pfnSSMPutMem(pSSM, afActiveStrms, sizeof(afActiveStrms));
3646
3647 LogFlowFuncLeaveRC(VINF_SUCCESS);
3648 return VINF_SUCCESS;
3649}
3650
3651
3652/**
3653 * Loads an AC'97 stream from SSM.
3654 *
3655 * @returns VBox status code.
3656 * @param pDevIns The device instance.
3657 * @param pSSM Saved state manager (SSM) handle to use.
3658 * @param pStream AC'97 stream to load.
3659 */
3660static int ichac97R3LoadStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStream)
3661{
3662 PAC97BMREGS pRegs = &pStream->Regs;
3663 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3664
3665 pHlp->pfnSSMGetU32(pSSM, &pRegs->bdbar);
3666 pHlp->pfnSSMGetU8( pSSM, &pRegs->civ);
3667 pHlp->pfnSSMGetU8( pSSM, &pRegs->lvi);
3668 pHlp->pfnSSMGetU16(pSSM, &pRegs->sr);
3669 pHlp->pfnSSMGetU16(pSSM, &pRegs->picb);
3670 pHlp->pfnSSMGetU8( pSSM, &pRegs->piv);
3671 pHlp->pfnSSMGetU8( pSSM, &pRegs->cr);
3672 pHlp->pfnSSMGetS32(pSSM, &pRegs->bd_valid);
3673 pHlp->pfnSSMGetU32(pSSM, &pRegs->bd.addr);
3674 return pHlp->pfnSSMGetU32(pSSM, &pRegs->bd.ctl_len);
3675}
3676
3677
3678/**
3679 * @callback_method_impl{FNSSMDEVLOADEXEC}
3680 */
3681static DECLCALLBACK(int) ichac97R3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
3682{
3683 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3684 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
3685 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3686
3687 LogRel2(("ichac97LoadExec: uVersion=%RU32, uPass=0x%x\n", uVersion, uPass));
3688
3689 AssertMsgReturn (uVersion == AC97_SAVED_STATE_VERSION, ("%RU32\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
3690 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
3691
3692 pHlp->pfnSSMGetU32(pSSM, &pThis->glob_cnt);
3693 pHlp->pfnSSMGetU32(pSSM, &pThis->glob_sta);
3694 pHlp->pfnSSMGetU32(pSSM, &pThis->cas);
3695
3696 /*
3697 * The order the streams are loaded here is critical (defined by
3698 * AC97SOUNDSOURCE_XX_INDEX), so don't touch!
3699 */
3700 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
3701 {
3702 int rc = ichac97R3LoadStream(pDevIns, pSSM, &pThis->aStreams[i]);
3703 AssertRCReturn(rc, rc);
3704 }
3705
3706 pHlp->pfnSSMGetMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
3707
3708 ichac97R3MixerRecordSelect(pThis, ichac97MixerGet(pThis, AC97_Record_Select));
3709 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER,
3710 ichac97MixerGet(pThis, AC97_Master_Volume_Mute));
3711 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT,
3712 ichac97MixerGet(pThis, AC97_PCM_Out_Volume_Mute));
3713 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN,
3714 ichac97MixerGet(pThis, AC97_Line_In_Volume_Mute));
3715 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Mic_Volume_Mute, PDMAUDIOMIXERCTL_MIC_IN,
3716 ichac97MixerGet(pThis, AC97_Mic_Volume_Mute));
3717 ichac97R3MixerSetGain(pThis, pThisCC, AC97_Record_Gain_Mic_Mute, PDMAUDIOMIXERCTL_MIC_IN,
3718 ichac97MixerGet(pThis, AC97_Record_Gain_Mic_Mute));
3719 ichac97R3MixerSetGain(pThis, pThisCC, AC97_Record_Gain_Mute, PDMAUDIOMIXERCTL_LINE_IN,
3720 ichac97MixerGet(pThis, AC97_Record_Gain_Mute));
3721 if (pThis->enmCodecModel == AC97CODEC_AD1980)
3722 if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_HPSEL)
3723 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Headphone_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER,
3724 ichac97MixerGet(pThis, AC97_Headphone_Volume_Mute));
3725
3726 /*
3727 * Again the stream order is set is stone.
3728 */
3729 uint8_t afActiveStrms[AC97SOUNDSOURCE_MAX];
3730 int rc = pHlp->pfnSSMGetMem(pSSM, afActiveStrms, sizeof(afActiveStrms));
3731 AssertRCReturn(rc, rc);
3732
3733 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
3734 {
3735 const bool fEnable = RT_BOOL(afActiveStrms[i]);
3736 const PAC97STREAM pStream = &pThis->aStreams[i];
3737 const PAC97STREAMR3 pStreamCC = &pThisCC->aStreams[i];
3738
3739 rc = ichac97R3StreamEnable(pDevIns, pThis, pThisCC, pStream, pStreamCC, fEnable);
3740 AssertRC(rc);
3741 if ( fEnable
3742 && RT_SUCCESS(rc))
3743 {
3744 /* Re-arm the timer for this stream. */
3745 /** @todo r=aeichner This causes a VM hang upon saved state resume when NetBSD is used as a guest
3746 * Stopping the timer if cTransferTicks is 0 is a workaround but needs further investigation,
3747 * see @bugref{9759} for more information. */
3748 if (pStreamCC->State.cTransferTicks)
3749 ichac97R3TimerSet(pDevIns, pStream, pStreamCC->State.cTransferTicks);
3750 else
3751 PDMDevHlpTimerStop(pDevIns, pStream->hTimer);
3752 }
3753
3754 /* Keep going. */
3755 }
3756
3757 pThis->bup_flag = 0;
3758 pThis->last_samp = 0;
3759
3760 return VINF_SUCCESS;
3761}
3762
3763
3764/*********************************************************************************************************************************
3765* Debug Info Items *
3766*********************************************************************************************************************************/
3767
3768/** Used by ichac97R3DbgInfoStream and ichac97R3DbgInfoBDL. */
3769static int ichac97R3DbgLookupStrmIdx(PCDBGFINFOHLP pHlp, const char *pszArgs)
3770{
3771 if (pszArgs && *pszArgs)
3772 {
3773 int32_t idxStream;
3774 int rc = RTStrToInt32Full(pszArgs, 0, &idxStream);
3775 if (RT_SUCCESS(rc) && idxStream >= -1 && idxStream < AC97_MAX_STREAMS)
3776 return idxStream;
3777 pHlp->pfnPrintf(pHlp, "Argument '%s' is not a valid stream number!\n", pszArgs);
3778 }
3779 return -1;
3780}
3781
3782
3783/**
3784 * Generic buffer descriptor list dumper.
3785 */
3786static void ichac97R3DbgPrintBdl(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream,
3787 PCDBGFINFOHLP pHlp, const char *pszPrefix)
3788{
3789 uint8_t const bLvi = pStream->Regs.lvi;
3790 uint8_t const bCiv = pStream->Regs.civ;
3791 pHlp->pfnPrintf(pHlp, "%sBDL for stream #%u: @ %#RX32 LB 0x100; CIV=%#04x LVI=%#04x:\n",
3792 pszPrefix, pStream->u8SD, pStream->Regs.bdbar, bCiv, bLvi);
3793 if (pStream->Regs.bdbar != 0)
3794 {
3795 /* Read all in one go. */
3796 AC97BDLE aBdl[AC97_MAX_BDLE];
3797 RT_ZERO(aBdl);
3798 PDMDevHlpPCIPhysRead(pDevIns, pStream->Regs.bdbar, aBdl, sizeof(aBdl));
3799
3800 /* Get the audio props for the stream so we can translate the sizes correctly. */
3801 PDMAUDIOPCMPROPS Props;
3802 ichach97R3CalcStreamProps(pThis, pStream->u8SD, &Props);
3803
3804 /* Dump them. */
3805 uint64_t cbTotal = 0;
3806 uint64_t cbValid = 0;
3807 for (unsigned i = 0; i < RT_ELEMENTS(aBdl); i++)
3808 {
3809 aBdl[i].addr = RT_LE2H_U32(aBdl[i].addr);
3810 aBdl[i].ctl_len = RT_LE2H_U32(aBdl[i].ctl_len);
3811
3812 bool const fValid = bCiv <= bLvi
3813 ? i >= bCiv && i <= bLvi
3814 : i >= bCiv || i <= bLvi;
3815
3816 uint32_t const cb = (aBdl[i].ctl_len & AC97_BD_LEN_MASK) * PDMAudioPropsSampleSize(&Props); /** @todo or frame size? OSDev says frame... */
3817 cbTotal += cb;
3818 if (fValid)
3819 cbValid += cb;
3820
3821 char szFlags[64];
3822 szFlags[0] = '\0';
3823 if (aBdl[i].ctl_len & ~(AC97_BD_LEN_MASK | AC97_BD_IOC | AC97_BD_BUP))
3824 RTStrPrintf(szFlags, sizeof(szFlags), " !!fFlags=%#x!!\n", aBdl[i].ctl_len & ~AC97_BD_LEN_MASK);
3825
3826 pHlp->pfnPrintf(pHlp, "%s %cBDLE%02u: %#010RX32 L %#06x / LB %#RX32 / %RU64ms%s%s%s%s\n",
3827 pszPrefix, fValid ? ' ' : '?', i, aBdl[i].addr,
3828 aBdl[i].ctl_len & AC97_BD_LEN_MASK, cb, PDMAudioPropsBytesToMilli(&Props, cb),
3829 aBdl[i].ctl_len & AC97_BD_IOC ? " ioc" : "",
3830 aBdl[i].ctl_len & AC97_BD_BUP ? " bup" : "",
3831 szFlags, !(aBdl[i].addr & 3) ? "" : " !!Addr!!");
3832 }
3833
3834 pHlp->pfnPrintf(pHlp, "%sTotal: %#RX64 bytes (%RU64), %RU64 ms; Valid: %#RX64 bytes (%RU64), %RU64 ms\n", pszPrefix,
3835 cbTotal, cbTotal, PDMAudioPropsBytesToMilli(&Props, cbTotal),
3836 cbValid, cbValid, PDMAudioPropsBytesToMilli(&Props, cbValid) );
3837 }
3838}
3839
3840
3841/**
3842 * @callback_method_impl{FNDBGFHANDLERDEV, ac97bdl}
3843 */
3844static DECLCALLBACK(void) ichac97R3DbgInfoBDL(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3845{
3846 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3847 int idxStream = ichac97R3DbgLookupStrmIdx(pHlp, pszArgs);
3848 if (idxStream != -1)
3849 ichac97R3DbgPrintBdl(pDevIns, pThis, &pThis->aStreams[idxStream], pHlp, "");
3850 else
3851 for (idxStream = 0; idxStream < AC97_MAX_STREAMS; ++idxStream)
3852 ichac97R3DbgPrintBdl(pDevIns, pThis, &pThis->aStreams[idxStream], pHlp, "");
3853}
3854
3855
3856/** Worker for ichac97R3DbgInfoStream. */
3857static void ichac97R3DbgPrintStream(PCDBGFINFOHLP pHlp, PAC97STREAM pStream, PAC97STREAMR3 pStreamR3)
3858{
3859 char szTmp[PDMAUDIOSTRMCFGTOSTRING_MAX];
3860 pHlp->pfnPrintf(pHlp, "Stream #%d: %s\n", pStream->u8SD,
3861 PDMAudioStrmCfgToString(&pStreamR3->State.Cfg, szTmp, sizeof(szTmp)));
3862 pHlp->pfnPrintf(pHlp, " BDBAR %#010RX32\n", pStream->Regs.bdbar);
3863 pHlp->pfnPrintf(pHlp, " CIV %#04RX8\n", pStream->Regs.civ);
3864 pHlp->pfnPrintf(pHlp, " LVI %#04RX8\n", pStream->Regs.lvi);
3865 pHlp->pfnPrintf(pHlp, " SR %#06RX16\n", pStream->Regs.sr);
3866 pHlp->pfnPrintf(pHlp, " PICB %#06RX16\n", pStream->Regs.picb);
3867 pHlp->pfnPrintf(pHlp, " PIV %#04RX8\n", pStream->Regs.piv);
3868 pHlp->pfnPrintf(pHlp, " CR %#04RX8\n", pStream->Regs.cr);
3869 if (pStream->Regs.bd_valid)
3870 {
3871 pHlp->pfnPrintf(pHlp, " BD.ADDR %#010RX32\n", pStream->Regs.bd.addr);
3872 pHlp->pfnPrintf(pHlp, " BD.LEN %#04RX16\n", (uint16_t)pStream->Regs.bd.ctl_len);
3873 pHlp->pfnPrintf(pHlp, " BD.CTL %#04RX16\n", (uint16_t)(pStream->Regs.bd.ctl_len >> 16));
3874 }
3875
3876 pHlp->pfnPrintf(pHlp, " offRead %#RX64\n", pStreamR3->State.offRead);
3877 pHlp->pfnPrintf(pHlp, " offWrite %#RX64\n", pStreamR3->State.offWrite);
3878 pHlp->pfnPrintf(pHlp, " uTimerHz %RU16\n", pStreamR3->State.uTimerHz);
3879 pHlp->pfnPrintf(pHlp, " cTransferTicks %RU64\n", pStreamR3->State.cTransferTicks);
3880 pHlp->pfnPrintf(pHlp, " cbTransferChunk %#RX32\n", pStreamR3->State.cbTransferChunk);
3881}
3882
3883
3884/**
3885 * @callback_method_impl{FNDBGFHANDLERDEV, ac97stream}
3886 */
3887static DECLCALLBACK(void) ichac97R3DbgInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3888{
3889 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3890 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
3891 int idxStream = ichac97R3DbgLookupStrmIdx(pHlp, pszArgs);
3892 if (idxStream != -1)
3893 ichac97R3DbgPrintStream(pHlp, &pThis->aStreams[idxStream], &pThisCC->aStreams[idxStream]);
3894 else
3895 for (idxStream = 0; idxStream < AC97_MAX_STREAMS; ++idxStream)
3896 ichac97R3DbgPrintStream(pHlp, &pThis->aStreams[idxStream], &pThisCC->aStreams[idxStream]);
3897}
3898
3899
3900/*********************************************************************************************************************************
3901* PDMIBASE *
3902*********************************************************************************************************************************/
3903
3904/**
3905 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
3906 */
3907static DECLCALLBACK(void *) ichac97R3QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
3908{
3909 PAC97STATER3 pThisCC = RT_FROM_MEMBER(pInterface, AC97STATER3, IBase);
3910 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
3911 return NULL;
3912}
3913
3914
3915/*********************************************************************************************************************************
3916* PDMDEVREG *
3917*********************************************************************************************************************************/
3918
3919/**
3920 * Destroys all AC'97 audio streams of the device.
3921 *
3922 * @param pDevIns The device AC'97 instance.
3923 * @param pThis The shared AC'97 state.
3924 * @param pThisCC The ring-3 AC'97 state.
3925 */
3926static void ichac97R3StreamsDestroy(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC)
3927{
3928 LogFlowFuncEnter();
3929
3930 /*
3931 * Destroy all AC'97 streams.
3932 */
3933 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
3934 ichac97R3StreamDestroy(pThisCC, &pThis->aStreams[i], &pThisCC->aStreams[i]);
3935
3936 /*
3937 * Destroy all sinks.
3938 */
3939 if (pThisCC->pSinkLineIn)
3940 {
3941 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pThisCC->pSinkLineIn, PDMAUDIODIR_IN, PDMAUDIOPATH_IN_LINE);
3942
3943 AudioMixerSinkDestroy(pThisCC->pSinkLineIn, pDevIns);
3944 pThisCC->pSinkLineIn = NULL;
3945 }
3946
3947 if (pThisCC->pSinkMicIn)
3948 {
3949 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pThisCC->pSinkMicIn, PDMAUDIODIR_IN, PDMAUDIOPATH_IN_MIC);
3950
3951 AudioMixerSinkDestroy(pThisCC->pSinkMicIn, pDevIns);
3952 pThisCC->pSinkMicIn = NULL;
3953 }
3954
3955 if (pThisCC->pSinkOut)
3956 {
3957 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pThisCC->pSinkOut, PDMAUDIODIR_OUT, PDMAUDIOPATH_OUT_FRONT);
3958
3959 AudioMixerSinkDestroy(pThisCC->pSinkOut, pDevIns);
3960 pThisCC->pSinkOut = NULL;
3961 }
3962}
3963
3964
3965/**
3966 * Powers off the device.
3967 *
3968 * @param pDevIns Device instance to power off.
3969 */
3970static DECLCALLBACK(void) ichac97R3PowerOff(PPDMDEVINS pDevIns)
3971{
3972 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
3973 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
3974
3975 LogRel2(("AC97: Powering off ...\n"));
3976
3977 /* Note: Involves mixer stream / sink destruction, so also do this here
3978 * instead of in ichac97R3Destruct(). */
3979 ichac97R3StreamsDestroy(pDevIns, pThis, pThisCC);
3980
3981 /*
3982 * Note: Destroy the mixer while powering off and *not* in ichac97R3Destruct,
3983 * giving the mixer the chance to release any references held to
3984 * PDM audio streams it maintains.
3985 */
3986 if (pThisCC->pMixer)
3987 {
3988 AudioMixerDestroy(pThisCC->pMixer, pDevIns);
3989 pThisCC->pMixer = NULL;
3990 }
3991}
3992
3993
3994/**
3995 * @interface_method_impl{PDMDEVREG,pfnReset}
3996 *
3997 * @remarks The original sources didn't install a reset handler, but it seems to
3998 * make sense to me so we'll do it.
3999 */
4000static DECLCALLBACK(void) ichac97R3Reset(PPDMDEVINS pDevIns)
4001{
4002 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
4003 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
4004
4005 LogRel(("AC97: Reset\n"));
4006
4007 /*
4008 * Reset the mixer too. The Windows XP driver seems to rely on
4009 * this. At least it wants to read the vendor id before it resets
4010 * the codec manually.
4011 */
4012 ichac97R3MixerReset(pThis, pThisCC);
4013
4014 /*
4015 * Reset all streams.
4016 */
4017 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
4018 {
4019 ichac97R3StreamEnable(pDevIns, pThis, pThisCC, &pThis->aStreams[i], &pThisCC->aStreams[i], false /* fEnable */);
4020 ichac97R3StreamReset(pThis, &pThis->aStreams[i], &pThisCC->aStreams[i]);
4021 }
4022
4023 /*
4024 * Reset mixer sinks.
4025 *
4026 * Do the reset here instead of in ichac97R3StreamReset();
4027 * the mixer sink(s) might still have data to be processed when an audio stream gets reset.
4028 */
4029 AudioMixerSinkReset(pThisCC->pSinkLineIn);
4030 AudioMixerSinkReset(pThisCC->pSinkMicIn);
4031 AudioMixerSinkReset(pThisCC->pSinkOut);
4032}
4033
4034
4035/**
4036 * Adds a specific AC'97 driver to the driver chain.
4037 *
4038 * Only called from ichac97R3Attach().
4039 *
4040 * @returns VBox status code.
4041 * @param pDevIns The device instance.
4042 * @param pThisCC The ring-3 AC'97 device state.
4043 * @param pDrv The AC'97 driver to add.
4044 */
4045static int ichac97R3MixerAddDrv(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, PAC97DRIVER pDrv)
4046{
4047 int rc = VINF_SUCCESS;
4048
4049 if (AudioHlpStreamCfgIsValid(&pThisCC->aStreams[AC97SOUNDSOURCE_PI_INDEX].State.Cfg))
4050 rc = ichac97R3MixerAddDrvStream(pDevIns, pThisCC->pSinkLineIn,
4051 &pThisCC->aStreams[AC97SOUNDSOURCE_PI_INDEX].State.Cfg, pDrv);
4052
4053 if (AudioHlpStreamCfgIsValid(&pThisCC->aStreams[AC97SOUNDSOURCE_PO_INDEX].State.Cfg))
4054 {
4055 int rc2 = ichac97R3MixerAddDrvStream(pDevIns, pThisCC->pSinkOut,
4056 &pThisCC->aStreams[AC97SOUNDSOURCE_PO_INDEX].State.Cfg, pDrv);
4057 if (RT_SUCCESS(rc))
4058 rc = rc2;
4059 }
4060
4061 if (AudioHlpStreamCfgIsValid(&pThisCC->aStreams[AC97SOUNDSOURCE_MC_INDEX].State.Cfg))
4062 {
4063 int rc2 = ichac97R3MixerAddDrvStream(pDevIns, pThisCC->pSinkMicIn,
4064 &pThisCC->aStreams[AC97SOUNDSOURCE_MC_INDEX].State.Cfg, pDrv);
4065 if (RT_SUCCESS(rc))
4066 rc = rc2;
4067 }
4068
4069 return rc;
4070}
4071
4072
4073/**
4074 * Worker for ichac97R3Construct() and ichac97R3Attach().
4075 *
4076 * @returns VBox status code.
4077 * @param pDevIns The device instance.
4078 * @param pThisCC The ring-3 AC'97 device state.
4079 * @param iLun The logical unit which is being attached.
4080 * @param ppDrv Attached driver instance on success. Optional.
4081 */
4082static int ichac97R3AttachInternal(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, unsigned iLun, PAC97DRIVER *ppDrv)
4083{
4084 /*
4085 * Attach driver.
4086 */
4087 char *pszDesc = RTStrAPrintf2("Audio driver port (AC'97) for LUN #%u", iLun);
4088 AssertLogRelReturn(pszDesc, VERR_NO_STR_MEMORY);
4089
4090 PPDMIBASE pDrvBase;
4091 int rc = PDMDevHlpDriverAttach(pDevIns, iLun, &pThisCC->IBase, &pDrvBase, pszDesc);
4092 if (RT_SUCCESS(rc))
4093 {
4094 PAC97DRIVER pDrv = (PAC97DRIVER)RTMemAllocZ(sizeof(AC97DRIVER));
4095 if (pDrv)
4096 {
4097 pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
4098 AssertPtr(pDrv->pConnector);
4099 if (RT_VALID_PTR(pDrv->pConnector))
4100 {
4101 pDrv->pDrvBase = pDrvBase;
4102 pDrv->uLUN = iLun;
4103 pDrv->pszDesc = pszDesc;
4104
4105 /* Attach to driver list if not attached yet. */
4106 if (!pDrv->fAttached)
4107 {
4108 RTListAppend(&pThisCC->lstDrv, &pDrv->Node);
4109 pDrv->fAttached = true;
4110 }
4111
4112 if (ppDrv)
4113 *ppDrv = pDrv;
4114 LogFunc(("LUN#%u: returns VINF_SUCCESS (pCon=%p)\n", iLun, pDrv->pConnector));
4115 return VINF_SUCCESS;
4116 }
4117 RTMemFree(pDrv);
4118 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
4119 }
4120 else
4121 rc = VERR_NO_MEMORY;
4122 }
4123 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4124 LogFunc(("No attached driver for LUN #%u\n", iLun));
4125 else
4126 LogFunc(("Attached driver for LUN #%u failed: %Rrc\n", iLun, rc));
4127
4128 RTStrFree(pszDesc);
4129 LogFunc(("LUN#%u: rc=%Rrc\n", iLun, rc));
4130 return rc;
4131}
4132
4133
4134/**
4135 * @interface_method_impl{PDMDEVREGR3,pfnAttach}
4136 */
4137static DECLCALLBACK(int) ichac97R3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4138{
4139 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
4140 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
4141 RT_NOREF(fFlags);
4142 LogFunc(("iLUN=%u, fFlags=%#x\n", iLUN, fFlags));
4143
4144 DEVAC97_LOCK(pDevIns, pThis);
4145
4146 PAC97DRIVER pDrv;
4147 int rc = ichac97R3AttachInternal(pDevIns, pThisCC, iLUN, &pDrv);
4148 if (RT_SUCCESS(rc))
4149 {
4150 int rc2 = ichac97R3MixerAddDrv(pDevIns, pThisCC, pDrv);
4151 if (RT_FAILURE(rc2))
4152 LogFunc(("ichac97R3MixerAddDrv failed with %Rrc (ignored)\n", rc2));
4153 }
4154
4155 DEVAC97_UNLOCK(pDevIns, pThis);
4156
4157 return rc;
4158}
4159
4160
4161/**
4162 * Removes a specific AC'97 driver from the driver chain and destroys its
4163 * associated streams.
4164 *
4165 * Only called from ichac97R3Detach().
4166 *
4167 * @param pDevIns The device instance.
4168 * @param pThisCC The ring-3 AC'97 device state.
4169 * @param pDrv AC'97 driver to remove.
4170 */
4171static void ichac97R3MixerRemoveDrv(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, PAC97DRIVER pDrv)
4172{
4173 if (pDrv->MicIn.pMixStrm)
4174 {
4175 AudioMixerSinkRemoveStream(pThisCC->pSinkMicIn, pDrv->MicIn.pMixStrm);
4176 AudioMixerStreamDestroy(pDrv->MicIn.pMixStrm, pDevIns, true /*fImmediate*/);
4177 pDrv->MicIn.pMixStrm = NULL;
4178 }
4179
4180 if (pDrv->LineIn.pMixStrm)
4181 {
4182 AudioMixerSinkRemoveStream(pThisCC->pSinkLineIn, pDrv->LineIn.pMixStrm);
4183 AudioMixerStreamDestroy(pDrv->LineIn.pMixStrm, pDevIns, true /*fImmediate*/);
4184 pDrv->LineIn.pMixStrm = NULL;
4185 }
4186
4187 if (pDrv->Out.pMixStrm)
4188 {
4189 AudioMixerSinkRemoveStream(pThisCC->pSinkOut, pDrv->Out.pMixStrm);
4190 AudioMixerStreamDestroy(pDrv->Out.pMixStrm, pDevIns, true /*fImmediate*/);
4191 pDrv->Out.pMixStrm = NULL;
4192 }
4193
4194 RTListNodeRemove(&pDrv->Node);
4195}
4196
4197
4198/**
4199 * @interface_method_impl{PDMDEVREG,pfnDetach}
4200 */
4201static DECLCALLBACK(void) ichac97R3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4202{
4203 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
4204 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
4205 RT_NOREF(fFlags);
4206
4207 LogFunc(("iLUN=%u, fFlags=0x%x\n", iLUN, fFlags));
4208
4209 DEVAC97_LOCK(pDevIns, pThis);
4210
4211 PAC97DRIVER pDrv;
4212 RTListForEach(&pThisCC->lstDrv, pDrv, AC97DRIVER, Node)
4213 {
4214 if (pDrv->uLUN == iLUN)
4215 {
4216 /* Remove the driver from our list and destory it's associated streams.
4217 This also will un-set the driver as a recording source (if associated). */
4218 ichac97R3MixerRemoveDrv(pDevIns, pThisCC, pDrv);
4219 LogFunc(("Detached LUN#%u\n", pDrv->uLUN));
4220
4221 DEVAC97_UNLOCK(pDevIns, pThis);
4222
4223 RTStrFree(pDrv->pszDesc);
4224 RTMemFree(pDrv);
4225 return;
4226 }
4227 }
4228
4229 DEVAC97_UNLOCK(pDevIns, pThis);
4230 LogFunc(("LUN#%u was not found\n", iLUN));
4231}
4232
4233
4234/**
4235 * @interface_method_impl{PDMDEVREG,pfnDestruct}
4236 */
4237static DECLCALLBACK(int) ichac97R3Destruct(PPDMDEVINS pDevIns)
4238{
4239 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); /* this shall come first */
4240 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
4241
4242 LogFlowFuncEnter();
4243
4244 PAC97DRIVER pDrv, pDrvNext;
4245 RTListForEachSafe(&pThisCC->lstDrv, pDrv, pDrvNext, AC97DRIVER, Node)
4246 {
4247 RTListNodeRemove(&pDrv->Node);
4248 RTMemFree(pDrv->pszDesc);
4249 RTMemFree(pDrv);
4250 }
4251
4252 /* Sanity. */
4253 Assert(RTListIsEmpty(&pThisCC->lstDrv));
4254
4255 /* We don't always go via PowerOff, so make sure the mixer is destroyed. */
4256 if (pThisCC->pMixer)
4257 {
4258 AudioMixerDestroy(pThisCC->pMixer, pDevIns);
4259 pThisCC->pMixer = NULL;
4260 }
4261
4262 return VINF_SUCCESS;
4263}
4264
4265
4266/**
4267 * @interface_method_impl{PDMDEVREG,pfnConstruct}
4268 */
4269static DECLCALLBACK(int) ichac97R3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
4270{
4271 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* this shall come first */
4272 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
4273 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3);
4274 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4275 Assert(iInstance == 0); RT_NOREF(iInstance);
4276
4277 /*
4278 * Initialize data so we can run the destructor without scewing up.
4279 */
4280 pThisCC->pDevIns = pDevIns;
4281 pThisCC->IBase.pfnQueryInterface = ichac97R3QueryInterface;
4282 RTListInit(&pThisCC->lstDrv);
4283
4284 /*
4285 * Validate and read configuration.
4286 */
4287 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "BufSizeInMs|BufSizeOutMs|Codec|TimerHz|DebugEnabled|DebugPathOut", "");
4288
4289 /** @devcfgm{ac97,BufSizeInMs,uint16_t,0,2000,0,ms}
4290 * The size of the DMA buffer for input streams expressed in milliseconds. */
4291 int rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeInMs", &pThis->cMsCircBufIn, 0);
4292 if (RT_FAILURE(rc))
4293 return PDMDEV_SET_ERROR(pDevIns, rc,
4294 N_("AC97 configuration error: failed to read 'BufSizeInMs' as 16-bit unsigned integer"));
4295 if (pThis->cMsCircBufIn > 2000)
4296 return PDMDEV_SET_ERROR(pDevIns, VERR_OUT_OF_RANGE,
4297 N_("AC97 configuration error: 'BufSizeInMs' is out of bound, max 2000 ms"));
4298
4299 /** @devcfgm{ac97,BufSizeOutMs,uint16_t,0,2000,0,ms}
4300 * The size of the DMA buffer for output streams expressed in milliseconds. */
4301 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "BufSizeOutMs", &pThis->cMsCircBufOut, 0);
4302 if (RT_FAILURE(rc))
4303 return PDMDEV_SET_ERROR(pDevIns, rc,
4304 N_("AC97 configuration error: failed to read 'BufSizeOutMs' as 16-bit unsigned integer"));
4305 if (pThis->cMsCircBufOut > 2000)
4306 return PDMDEV_SET_ERROR(pDevIns, VERR_OUT_OF_RANGE,
4307 N_("AC97 configuration error: 'BufSizeOutMs' is out of bound, max 2000 ms"));
4308
4309 /** @devcfgm{ac97,TimerHz,uint16_t,10,1000,100,ms}
4310 * Currently the approximate rate at which the asynchronous I/O threads move
4311 * data from/to the DMA buffer, thru the mixer and drivers stack, and
4312 * to/from the host device/whatever. (It does NOT govern any DMA timer rate any
4313 * more as might be hinted at by the name.) */
4314 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "TimerHz", &pThis->uTimerHz, AC97_TIMER_HZ_DEFAULT);
4315 if (RT_FAILURE(rc))
4316 return PDMDEV_SET_ERROR(pDevIns, rc,
4317 N_("AC'97 configuration error: failed to read 'TimerHz' as a 16-bit unsigned integer"));
4318 if (pThis->uTimerHz < 10 || pThis->uTimerHz > 1000)
4319 return PDMDEV_SET_ERROR(pDevIns, VERR_OUT_OF_RANGE,
4320 N_("AC'97 configuration error: 'TimerHz' is out of range (10-1000 Hz)"));
4321
4322 if (pThis->uTimerHz != AC97_TIMER_HZ_DEFAULT)
4323 LogRel(("AC97: Using custom device timer rate: %RU16 Hz\n", pThis->uTimerHz));
4324
4325 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DebugEnabled", &pThisCC->Dbg.fEnabled, false);
4326 if (RT_FAILURE(rc))
4327 return PDMDEV_SET_ERROR(pDevIns, rc,
4328 N_("AC97 configuration error: failed to read debugging enabled flag as boolean"));
4329
4330 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "DebugPathOut", &pThisCC->Dbg.pszOutPath, NULL);
4331 if (RT_FAILURE(rc))
4332 return PDMDEV_SET_ERROR(pDevIns, rc,
4333 N_("AC97 configuration error: failed to read debugging output path flag as string"));
4334
4335 if (pThisCC->Dbg.fEnabled)
4336 LogRel2(("AC97: Debug output will be saved to '%s'\n", pThisCC->Dbg.pszOutPath));
4337
4338 /*
4339 * The AD1980 codec (with corresponding PCI subsystem vendor ID) is whitelisted
4340 * in the Linux kernel; Linux makes no attempt to measure the data rate and assumes
4341 * 48 kHz rate, which is exactly what we need. Same goes for AD1981B.
4342 */
4343 char szCodec[20];
4344 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "Codec", &szCodec[0], sizeof(szCodec), "STAC9700");
4345 if (RT_FAILURE(rc))
4346 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
4347 N_("AC'97 configuration error: Querying \"Codec\" as string failed"));
4348 if (!strcmp(szCodec, "STAC9700"))
4349 pThis->enmCodecModel = AC97CODEC_STAC9700;
4350 else if (!strcmp(szCodec, "AD1980"))
4351 pThis->enmCodecModel = AC97CODEC_AD1980;
4352 else if (!strcmp(szCodec, "AD1981B"))
4353 pThis->enmCodecModel = AC97CODEC_AD1981B;
4354 else
4355 return PDMDevHlpVMSetError(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, RT_SRC_POS,
4356 N_("AC'97 configuration error: The \"Codec\" value \"%s\" is unsupported"), szCodec);
4357
4358 LogRel(("AC97: Using codec '%s'\n", szCodec));
4359
4360 /*
4361 * Use an own critical section for the device instead of the default
4362 * one provided by PDM. This allows fine-grained locking in combination
4363 * with TM when timer-specific stuff is being called in e.g. the MMIO handlers.
4364 */
4365 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "AC'97");
4366 AssertRCReturn(rc, rc);
4367
4368 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
4369 AssertRCReturn(rc, rc);
4370
4371 /*
4372 * Initialize data (most of it anyway).
4373 */
4374 /* PCI Device */
4375 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
4376 PCIDevSetVendorId(pPciDev, 0x8086); /* 00 ro - intel. */ Assert(pPciDev->abConfig[0x00] == 0x86); Assert(pPciDev->abConfig[0x01] == 0x80);
4377 PCIDevSetDeviceId(pPciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */ Assert(pPciDev->abConfig[0x02] == 0x15); Assert(pPciDev->abConfig[0x03] == 0x24);
4378 PCIDevSetCommand(pPciDev, 0x0000); /* 04 rw,ro - pcicmd. */ Assert(pPciDev->abConfig[0x04] == 0x00); Assert(pPciDev->abConfig[0x05] == 0x00);
4379 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);
4380 PCIDevSetRevisionId(pPciDev, 0x01); /* 08 ro - rid. */ Assert(pPciDev->abConfig[0x08] == 0x01);
4381 PCIDevSetClassProg(pPciDev, 0x00); /* 09 ro - pi. */ Assert(pPciDev->abConfig[0x09] == 0x00);
4382 PCIDevSetClassSub(pPciDev, 0x01); /* 0a ro - scc; 01 == Audio. */ Assert(pPciDev->abConfig[0x0a] == 0x01);
4383 PCIDevSetClassBase(pPciDev, 0x04); /* 0b ro - bcc; 04 == multimedia.*/Assert(pPciDev->abConfig[0x0b] == 0x04);
4384 PCIDevSetHeaderType(pPciDev, 0x00); /* 0e ro - headtyp. */ Assert(pPciDev->abConfig[0x0e] == 0x00);
4385 PCIDevSetBaseAddress(pPciDev, 0, /* 10 rw - nambar - native audio mixer base. */
4386 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);
4387 PCIDevSetBaseAddress(pPciDev, 1, /* 14 rw - nabmbar - native audio bus mastering. */
4388 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);
4389 PCIDevSetInterruptLine(pPciDev, 0x00); /* 3c rw. */ Assert(pPciDev->abConfig[0x3c] == 0x00);
4390 PCIDevSetInterruptPin(pPciDev, 0x01); /* 3d ro - INTA#. */ Assert(pPciDev->abConfig[0x3d] == 0x01);
4391
4392 if (pThis->enmCodecModel == AC97CODEC_AD1980)
4393 {
4394 PCIDevSetSubSystemVendorId(pPciDev, 0x1028); /* 2c ro - Dell.) */
4395 PCIDevSetSubSystemId(pPciDev, 0x0177); /* 2e ro. */
4396 }
4397 else if (pThis->enmCodecModel == AC97CODEC_AD1981B)
4398 {
4399 PCIDevSetSubSystemVendorId(pPciDev, 0x1028); /* 2c ro - Dell.) */
4400 PCIDevSetSubSystemId(pPciDev, 0x01ad); /* 2e ro. */
4401 }
4402 else
4403 {
4404 PCIDevSetSubSystemVendorId(pPciDev, 0x8086); /* 2c ro - Intel.) */
4405 PCIDevSetSubSystemId(pPciDev, 0x0000); /* 2e ro. */
4406 }
4407
4408 /*
4409 * Register the PCI device and associated I/O regions.
4410 */
4411 rc = PDMDevHlpPCIRegister(pDevIns, pPciDev);
4412 if (RT_FAILURE(rc))
4413 return rc;
4414
4415 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, 0 /*iPciRegion*/, 256 /*cPorts*/,
4416 ichac97IoPortNamWrite, ichac97IoPortNamRead, NULL /*pvUser*/,
4417 "ICHAC97 NAM", NULL /*paExtDescs*/, &pThis->hIoPortsNam);
4418 AssertRCReturn(rc, rc);
4419
4420 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, 1 /*iPciRegion*/, 64 /*cPorts*/,
4421 ichac97IoPortNabmWrite, ichac97IoPortNabmRead, NULL /*pvUser*/,
4422 "ICHAC97 NABM", g_aNabmPorts, &pThis->hIoPortsNabm);
4423 AssertRCReturn(rc, rc);
4424
4425 /*
4426 * Saved state.
4427 */
4428 rc = PDMDevHlpSSMRegister(pDevIns, AC97_SAVED_STATE_VERSION, sizeof(*pThis), ichac97R3SaveExec, ichac97R3LoadExec);
4429 if (RT_FAILURE(rc))
4430 return rc;
4431
4432 /*
4433 * Attach drivers. We ASSUME they are configured consecutively without any
4434 * gaps, so we stop when we hit the first LUN w/o a driver configured.
4435 */
4436 for (unsigned iLun = 0; ; iLun++)
4437 {
4438 AssertBreak(iLun < UINT8_MAX);
4439 LogFunc(("Trying to attach driver for LUN#%u ...\n", iLun));
4440 rc = ichac97R3AttachInternal(pDevIns, pThisCC, iLun, NULL /* ppDrv */);
4441 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4442 {
4443 LogFunc(("cLUNs=%u\n", iLun));
4444 break;
4445 }
4446 AssertLogRelMsgReturn(RT_SUCCESS(rc), ("LUN#%u: rc=%Rrc\n", iLun, rc), rc);
4447 }
4448
4449 uint32_t fMixer = AUDMIXER_FLAGS_NONE;
4450 if (pThisCC->Dbg.fEnabled)
4451 fMixer |= AUDMIXER_FLAGS_DEBUG;
4452
4453 rc = AudioMixerCreate("AC'97 Mixer", 0 /* uFlags */, &pThisCC->pMixer);
4454 AssertRCReturn(rc, rc);
4455
4456 rc = AudioMixerCreateSink(pThisCC->pMixer, "Line In",
4457 PDMAUDIODIR_IN, pDevIns, &pThisCC->pSinkLineIn);
4458 AssertRCReturn(rc, rc);
4459 rc = AudioMixerCreateSink(pThisCC->pMixer, "Microphone In",
4460 PDMAUDIODIR_IN, pDevIns, &pThisCC->pSinkMicIn);
4461 AssertRCReturn(rc, rc);
4462 rc = AudioMixerCreateSink(pThisCC->pMixer, "PCM Output",
4463 PDMAUDIODIR_OUT, pDevIns, &pThisCC->pSinkOut);
4464 AssertRCReturn(rc, rc);
4465
4466 /*
4467 * Create all hardware streams.
4468 */
4469 AssertCompile(RT_ELEMENTS(pThis->aStreams) == AC97_MAX_STREAMS);
4470 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
4471 {
4472 rc = ichac97R3StreamConstruct(pThisCC, &pThis->aStreams[i], &pThisCC->aStreams[i], i /* SD# */);
4473 AssertRCReturn(rc, rc);
4474 }
4475
4476 /*
4477 * Create the emulation timers (one per stream).
4478 *
4479 * We must the critical section for the timers as the device has a
4480 * noop section associated with it.
4481 *
4482 * Note: Use TMCLOCK_VIRTUAL_SYNC here, as the guest's AC'97 driver
4483 * relies on exact (virtual) DMA timing and uses DMA Position Buffers
4484 * instead of the LPIB registers.
4485 */
4486 /** @todo r=bird: The need to use virtual sync is perhaps because TM
4487 * doesn't schedule regular TMCLOCK_VIRTUAL timers as accurately as it
4488 * should (VT-x preemption timer, etc). Hope to address that before
4489 * long. @bugref{9943}. */
4490 static const char * const s_apszNames[] = { "AC97 PI", "AC97 PO", "AC97 MC" };
4491 AssertCompile(RT_ELEMENTS(s_apszNames) == AC97_MAX_STREAMS);
4492 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
4493 {
4494 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, ichac97R3Timer, &pThis->aStreams[i],
4495 TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_RING0, s_apszNames[i], &pThis->aStreams[i].hTimer);
4496 AssertRCReturn(rc, rc);
4497
4498 rc = PDMDevHlpTimerSetCritSect(pDevIns, pThis->aStreams[i].hTimer, &pThis->CritSect);
4499 AssertRCReturn(rc, rc);
4500 }
4501
4502 ichac97R3Reset(pDevIns);
4503
4504 /*
4505 * Info items.
4506 */
4507 //PDMDevHlpDBGFInfoRegister(pDevIns, "ac97", "AC'97 registers. (ac97 [register case-insensitive])", ichac97R3DbgInfo);
4508 PDMDevHlpDBGFInfoRegister(pDevIns, "ac97bdl", "AC'97 buffer descriptor list (BDL). (ac97bdl [stream number])",
4509 ichac97R3DbgInfoBDL);
4510 PDMDevHlpDBGFInfoRegister(pDevIns, "ac97stream", "AC'97 stream info. (ac97stream [stream number])", ichac97R3DbgInfoStream);
4511 //PDMDevHlpDBGFInfoRegister(pDevIns, "ac97mixer", "AC'97 mixer state.", ichac97R3DbgInfoMixer);
4512
4513 /*
4514 * Register statistics.
4515 */
4516 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatUnimplementedNabmReads, STAMTYPE_COUNTER, "UnimplementedNabmReads", STAMUNIT_OCCURENCES, "Unimplemented NABM register reads.");
4517 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatUnimplementedNabmWrites, STAMTYPE_COUNTER, "UnimplementedNabmWrites", STAMUNIT_OCCURENCES, "Unimplemented NABM register writes.");
4518# ifdef VBOX_WITH_STATISTICS
4519 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer, STAMTYPE_PROFILE, "Timer", STAMUNIT_TICKS_PER_CALL, "Profiling ichac97Timer.");
4520# endif
4521 for (unsigned idxStream = 0; idxStream < RT_ELEMENTS(pThis->aStreams); idxStream++)
4522 {
4523 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.cbTransferChunk, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
4524 "Bytes to transfer in the current DMA period.", "Stream%u/cbTransferChunk", idxStream);
4525 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].Regs.cr, STAMTYPE_X8, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
4526 "Control register (CR), bit 0 is the run bit.", "Stream%u/reg-CR", idxStream);
4527 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].Regs.sr, STAMTYPE_X16, STAMVISIBILITY_ALWAYS, STAMUNIT_NONE,
4528 "Status register (SR).", "Stream%u/reg-SR", idxStream);
4529 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.Cfg.Props.uHz, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_HZ,
4530 "The stream frequency.", "Stream%u/Hz", idxStream);
4531 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.Cfg.Props.cbFrame, STAMTYPE_U8, STAMVISIBILITY_USED, STAMUNIT_BYTES,
4532 "The frame size.", "Stream%u/FrameSize", idxStream);
4533 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.offRead, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
4534 "Virtual internal buffer read position.", "Stream%u/offRead", idxStream);
4535 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.offWrite, STAMTYPE_U64, STAMVISIBILITY_USED, STAMUNIT_BYTES,
4536 "Virtual internal buffer write position.", "Stream%u/offWrite", idxStream);
4537 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaBufSize, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
4538 "Size of the internal DMA buffer.", "Stream%u/DMABufSize", idxStream);
4539 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaBufUsed, STAMTYPE_U32, STAMVISIBILITY_USED, STAMUNIT_BYTES,
4540 "Number of bytes used in the internal DMA buffer.", "Stream%u/DMABufUsed", idxStream);
4541 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowProblems, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
4542 "Number of internal DMA buffer problems.", "Stream%u/DMABufferProblems", idxStream);
4543 if (ichac97R3GetDirFromSD(idxStream) == PDMAUDIODIR_OUT)
4544 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
4545 "Number of internal DMA buffer overflows.", "Stream%u/DMABufferOverflows", idxStream);
4546 else
4547 {
4548 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
4549 "Number of internal DMA buffer underuns.", "Stream%u/DMABufferUnderruns", idxStream);
4550 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrorBytes, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES,
4551 "Number of bytes of silence added to cope with underruns.", "Stream%u/DMABufferSilence", idxStream);
4552 }
4553
4554 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatStart, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
4555 "Starting the stream.", "Stream%u/Start", idxStream);
4556 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatStop, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
4557 "Stopping the stream.", "Stream%u/Stop", idxStream);
4558 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatReset, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
4559 "Resetting the stream.", "Stream%u/Reset", idxStream);
4560 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatReSetUpChanged, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
4561 "ichac97R3StreamReSetUp when recreating the streams.", "Stream%u/ReSetUp-Change", idxStream);
4562 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatReSetUpSame, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_NS_PER_CALL,
4563 "ichac97R3StreamReSetUp when no change.", "Stream%u/ReSetUp-NoChange", idxStream);
4564 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatWriteCr, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
4565 "CR register writes.", "Stream%u/WriteCr", idxStream);
4566 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatWriteLviRecover, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
4567 "LVI register writes recovering from underflow.", "Stream%u/WriteLviRecover", idxStream);
4568 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].StatWriteLvi, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
4569 "LVI register writes (non-recoving).", "Stream%u/WriteLvi", idxStream);
4570 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].StatWriteSr1, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
4571 "SR register 1-byte writes.", "Stream%u/WriteSr-1byte", idxStream);
4572 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].StatWriteSr2, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
4573 "SR register 2-byte writes.", "Stream%u/WriteSr-2byte", idxStream);
4574 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStreams[idxStream].StatWriteBdBar, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
4575 "BDBAR register writes.", "Stream%u/WriteBdBar", idxStream);
4576 }
4577
4578 LogFlowFuncLeaveRC(VINF_SUCCESS);
4579 return VINF_SUCCESS;
4580}
4581
4582#else /* !IN_RING3 */
4583
4584/**
4585 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
4586 */
4587static DECLCALLBACK(int) ichac97RZConstruct(PPDMDEVINS pDevIns)
4588{
4589 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
4590 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE);
4591
4592 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
4593 AssertRCReturn(rc, rc);
4594
4595 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsNam, ichac97IoPortNamWrite, ichac97IoPortNamRead, NULL /*pvUser*/);
4596 AssertRCReturn(rc, rc);
4597 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsNabm, ichac97IoPortNabmWrite, ichac97IoPortNabmRead, NULL /*pvUser*/);
4598 AssertRCReturn(rc, rc);
4599
4600 return VINF_SUCCESS;
4601}
4602
4603#endif /* !IN_RING3 */
4604
4605/**
4606 * The device registration structure.
4607 */
4608const PDMDEVREG g_DeviceICHAC97 =
4609{
4610 /* .u32Version = */ PDM_DEVREG_VERSION,
4611 /* .uReserved0 = */ 0,
4612 /* .szName = */ "ichac97",
4613 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE
4614 | PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION /* stream clearnup with working drivers */,
4615 /* .fClass = */ PDM_DEVREG_CLASS_AUDIO,
4616 /* .cMaxInstances = */ 1,
4617 /* .uSharedVersion = */ 42,
4618 /* .cbInstanceShared = */ sizeof(AC97STATE),
4619 /* .cbInstanceCC = */ CTX_EXPR(sizeof(AC97STATER3), 0, 0),
4620 /* .cbInstanceRC = */ 0,
4621 /* .cMaxPciDevices = */ 1,
4622 /* .cMaxMsixVectors = */ 0,
4623 /* .pszDescription = */ "ICH AC'97 Audio Controller",
4624#if defined(IN_RING3)
4625 /* .pszRCMod = */ "VBoxDDRC.rc",
4626 /* .pszR0Mod = */ "VBoxDDR0.r0",
4627 /* .pfnConstruct = */ ichac97R3Construct,
4628 /* .pfnDestruct = */ ichac97R3Destruct,
4629 /* .pfnRelocate = */ NULL,
4630 /* .pfnMemSetup = */ NULL,
4631 /* .pfnPowerOn = */ NULL,
4632 /* .pfnReset = */ ichac97R3Reset,
4633 /* .pfnSuspend = */ NULL,
4634 /* .pfnResume = */ NULL,
4635 /* .pfnAttach = */ ichac97R3Attach,
4636 /* .pfnDetach = */ ichac97R3Detach,
4637 /* .pfnQueryInterface = */ NULL,
4638 /* .pfnInitComplete = */ NULL,
4639 /* .pfnPowerOff = */ ichac97R3PowerOff,
4640 /* .pfnSoftReset = */ NULL,
4641 /* .pfnReserved0 = */ NULL,
4642 /* .pfnReserved1 = */ NULL,
4643 /* .pfnReserved2 = */ NULL,
4644 /* .pfnReserved3 = */ NULL,
4645 /* .pfnReserved4 = */ NULL,
4646 /* .pfnReserved5 = */ NULL,
4647 /* .pfnReserved6 = */ NULL,
4648 /* .pfnReserved7 = */ NULL,
4649#elif defined(IN_RING0)
4650 /* .pfnEarlyConstruct = */ NULL,
4651 /* .pfnConstruct = */ ichac97RZConstruct,
4652 /* .pfnDestruct = */ NULL,
4653 /* .pfnFinalDestruct = */ NULL,
4654 /* .pfnRequest = */ NULL,
4655 /* .pfnReserved0 = */ NULL,
4656 /* .pfnReserved1 = */ NULL,
4657 /* .pfnReserved2 = */ NULL,
4658 /* .pfnReserved3 = */ NULL,
4659 /* .pfnReserved4 = */ NULL,
4660 /* .pfnReserved5 = */ NULL,
4661 /* .pfnReserved6 = */ NULL,
4662 /* .pfnReserved7 = */ NULL,
4663#elif defined(IN_RC)
4664 /* .pfnConstruct = */ ichac97RZConstruct,
4665 /* .pfnReserved0 = */ NULL,
4666 /* .pfnReserved1 = */ NULL,
4667 /* .pfnReserved2 = */ NULL,
4668 /* .pfnReserved3 = */ NULL,
4669 /* .pfnReserved4 = */ NULL,
4670 /* .pfnReserved5 = */ NULL,
4671 /* .pfnReserved6 = */ NULL,
4672 /* .pfnReserved7 = */ NULL,
4673#else
4674# error "Not in IN_RING3, IN_RING0 or IN_RC!"
4675#endif
4676 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
4677};
4678
4679#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
4680
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