VirtualBox

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

Last change on this file since 76179 was 76179, checked in by vboxsync, 6 years ago

Audio/AC97: Fixed audio delays by using the same way of (Hz- and time-based) calculations as the HDA emulation utilizes. While at it, also implemented separate timers for each stream (as for HDA also), helping to keep timing per stream more accurate.

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