VirtualBox

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

Last change on this file since 82358 was 82358, checked in by vboxsync, 5 years ago

DevIchAc97: Set new-style flag. bugref:9218

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