VirtualBox

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

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

Audio: Removed PDMAUDIOSTREAMCFG::enmLayout and PDMAUDIOSTREAMLAYOUT. bugref:9890

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