VirtualBox

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

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

DevIchAc97: Renamed a couple of functions. bugref:9890

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