VirtualBox

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

Last change on this file since 64982 was 64982, checked in by vboxsync, 8 years ago

Build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 117.1 KB
Line 
1/* $Id: DevIchAc97.cpp 64982 2016-12-21 13:28:21Z vboxsync $ */
2/** @file
3 * DevIchAc97 - VBox ICH AC97 Audio Controller.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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/*
50 * Enables asynchronous audio data handling
51 * to speed up the actual DMA data routines and keeping up
52 * audio processing out of EMT as much as possible.
53 */
54#define VBOX_WITH_AUDIO_AC97_ASYNC_IO
55
56#if 0
57/*
58 * AC97_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
59 * to a file on the host. Be sure to adjust AC97_DEBUG_DUMP_PCM_DATA_PATH
60 * to your needs before using this!
61 */
62# define AC97_DEBUG_DUMP_PCM_DATA
63# ifdef RT_OS_WINDOWS
64# define AC97_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
65# else
66# define AC97_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
67# endif
68#endif
69
70/** Current saved state version. */
71#define AC97_SSM_VERSION 1
72
73/** Default timer frequency (in Hz). */
74#define AC97_TIMER_HZ 100
75
76#define AC97_SR_FIFOE RT_BIT(4) /* rwc, FIFO error. */
77#define AC97_SR_BCIS RT_BIT(3) /* rwc, Buffer completion interrupt status. */
78#define AC97_SR_LVBCI RT_BIT(2) /* rwc, Last valid buffer completion interrupt. */
79#define AC97_SR_CELV RT_BIT(1) /* ro, Current equals last valid. */
80#define AC97_SR_DCH RT_BIT(0) /* ro, Controller halted. */
81#define AC97_SR_VALID_MASK (RT_BIT(5) - 1)
82#define AC97_SR_WCLEAR_MASK (AC97_SR_FIFOE | AC97_SR_BCIS | AC97_SR_LVBCI)
83#define AC97_SR_RO_MASK (AC97_SR_DCH | AC97_SR_CELV)
84#define AC97_SR_INT_MASK (AC97_SR_FIFOE | AC97_SR_BCIS | AC97_SR_LVBCI)
85
86#define AC97_CR_IOCE RT_BIT(4) /* rw, Interrupt On Completion Enable. */
87#define AC97_CR_FEIE RT_BIT(3) /* rw FIFO Error Interrupt Enable. */
88#define AC97_CR_LVBIE RT_BIT(2) /* rw Last Valid Buffer Interrupt Enable. */
89#define AC97_CR_RR RT_BIT(1) /* rw Reset Registers. */
90#define AC97_CR_RPBM RT_BIT(0) /* rw Run/Pause Bus Master. */
91#define AC97_CR_VALID_MASK (RT_BIT(5) - 1)
92#define AC97_CR_DONT_CLEAR_MASK (AC97_CR_IOCE | AC97_CR_FEIE | AC97_CR_LVBIE)
93
94#define AC97_GC_WR 4 /* rw Warm reset. */
95#define AC97_GC_CR 2 /* rw Cold reset. */
96#define AC97_GC_VALID_MASK (RT_BIT(6) - 1)
97
98#define AC97_GS_MD3 RT_BIT(17) /* rw */
99#define AC97_GS_AD3 RT_BIT(16) /* rw */
100#define AC97_GS_RCS RT_BIT(15) /* rwc */
101#define AC97_GS_B3S12 RT_BIT(14) /* ro */
102#define AC97_GS_B2S12 RT_BIT(13) /* ro */
103#define AC97_GS_B1S12 RT_BIT(12) /* ro */
104#define AC97_GS_S1R1 RT_BIT(11) /* rwc */
105#define AC97_GS_S0R1 RT_BIT(10) /* rwc */
106#define AC97_GS_S1CR RT_BIT(9) /* ro */
107#define AC97_GS_S0CR RT_BIT(8) /* ro */
108#define AC97_GS_MINT RT_BIT(7) /* ro */
109#define AC97_GS_POINT RT_BIT(6) /* ro */
110#define AC97_GS_PIINT RT_BIT(5) /* ro */
111#define AC97_GS_RSRVD (RT_BIT(4)|RT_BIT(3))
112#define AC97_GS_MOINT RT_BIT(2) /* ro */
113#define AC97_GS_MIINT RT_BIT(1) /* ro */
114#define AC97_GS_GSCI RT_BIT(0) /* rwc */
115#define AC97_GS_RO_MASK (AC97_GS_B3S12 | \
116 AC97_GS_B2S12 | \
117 AC97_GS_B1S12 | \
118 AC97_GS_S1CR | \
119 AC97_GS_S0CR | \
120 AC97_GS_MINT | \
121 AC97_GS_POINT | \
122 AC97_GS_PIINT | \
123 AC97_GS_RSRVD | \
124 AC97_GS_MOINT | \
125 AC97_GS_MIINT)
126#define AC97_GS_VALID_MASK (RT_BIT(18) - 1)
127#define AC97_GS_WCLEAR_MASK (AC97_GS_RCS|AC97_GS_S1R1|AC97_GS_S0R1|AC97_GS_GSCI)
128
129/** @name Buffer Descriptor (BD).
130 * @{ */
131#define AC97_BD_IOC RT_BIT(31) /**< Interrupt on Completion. */
132#define AC97_BD_BUP RT_BIT(30) /**< Buffer Underrun Policy. */
133
134#define AC97_BD_MAX_LEN_MASK 0xFFFE
135/** @} */
136
137/** @name Extended Audio Status and Control Register (EACS).
138 * @{ */
139#define AC97_EACS_VRA 1 /**< Variable Rate Audio (4.2.1.1). */
140#define AC97_EACS_VRM 8 /**< Variable Rate Mic Audio (4.2.1.1). */
141/** @} */
142
143/** @name Baseline Audio Register Set (BARS).
144 * @{ */
145#define AC97_BARS_VOL_MASK 0x1f /**< Volume mask for the Baseline Audio Register Set (5.7.2). */
146#define AC97_BARS_VOL_STEPS 31 /**< Volume steps for the Baseline Audio Register Set (5.7.2). */
147#define AC97_BARS_VOL_MUTE_SHIFT 15 /**< Mute bit shift for the Baseline Audio Register Set (5.7.2). */
148/** @} */
149
150/* AC'97 uses 1.5dB steps, we use 0.375dB steps: 1 AC'97 step equals 4 PDM steps. */
151#define AC97_DB_FACTOR 4
152
153#define AC97_REC_MASK 7
154enum
155{
156 AC97_REC_MIC = 0,
157 AC97_REC_CD,
158 AC97_REC_VIDEO,
159 AC97_REC_AUX,
160 AC97_REC_LINE_IN,
161 AC97_REC_STEREO_MIX,
162 AC97_REC_MONO_MIX,
163 AC97_REC_PHONE
164};
165
166enum
167{
168 AC97_Reset = 0x00,
169 AC97_Master_Volume_Mute = 0x02,
170 AC97_Headphone_Volume_Mute = 0x04, /** Also known as AUX, see table 16, section 5.7. */
171 AC97_Master_Volume_Mono_Mute = 0x06,
172 AC97_Master_Tone_RL = 0x08,
173 AC97_PC_BEEP_Volume_Mute = 0x0A,
174 AC97_Phone_Volume_Mute = 0x0C,
175 AC97_Mic_Volume_Mute = 0x0E,
176 AC97_Line_In_Volume_Mute = 0x10,
177 AC97_CD_Volume_Mute = 0x12,
178 AC97_Video_Volume_Mute = 0x14,
179 AC97_Aux_Volume_Mute = 0x16,
180 AC97_PCM_Out_Volume_Mute = 0x18,
181 AC97_Record_Select = 0x1A,
182 AC97_Record_Gain_Mute = 0x1C,
183 AC97_Record_Gain_Mic_Mute = 0x1E,
184 AC97_General_Purpose = 0x20,
185 AC97_3D_Control = 0x22,
186 AC97_AC_97_RESERVED = 0x24,
187 AC97_Powerdown_Ctrl_Stat = 0x26,
188 AC97_Extended_Audio_ID = 0x28,
189 AC97_Extended_Audio_Ctrl_Stat = 0x2A,
190 AC97_PCM_Front_DAC_Rate = 0x2C,
191 AC97_PCM_Surround_DAC_Rate = 0x2E,
192 AC97_PCM_LFE_DAC_Rate = 0x30,
193 AC97_PCM_LR_ADC_Rate = 0x32,
194 AC97_MIC_ADC_Rate = 0x34,
195 AC97_6Ch_Vol_C_LFE_Mute = 0x36,
196 AC97_6Ch_Vol_L_R_Surround_Mute = 0x38,
197 AC97_Vendor_Reserved = 0x58,
198 AC97_AD_Misc = 0x76,
199 AC97_Vendor_ID1 = 0x7c,
200 AC97_Vendor_ID2 = 0x7e
201};
202
203/* Codec models. */
204typedef enum
205{
206 AC97_CODEC_STAC9700 = 0, /* SigmaTel STAC9700 */
207 AC97_CODEC_AD1980, /* Analog Devices AD1980 */
208 AC97_CODEC_AD1981B /* Analog Devices AD1981B */
209} AC97CODEC;
210
211/* Analog Devices miscellaneous regiter bits used in AD1980. */
212#define AC97_AD_MISC_LOSEL RT_BIT(5) /* Surround (rear) goes to line out outputs. */
213#define AC97_AD_MISC_HPSEL RT_BIT(10) /* PCM (front) goes to headphone outputs. */
214
215#define ICHAC97STATE_2_DEVINS(a_pAC97) ((a_pAC97)->pDevInsR3)
216
217enum
218{
219 BUP_SET = RT_BIT(0),
220 BUP_LAST = RT_BIT(1)
221};
222
223/** Emits registers for a specific (Native Audio Bus Master BAR) NABMBAR. */
224#define AC97_NABMBAR_REGS(prefix, off) \
225 enum { \
226 prefix ## _BDBAR = off, /* Buffer Descriptor Base Address */ \
227 prefix ## _CIV = off + 4, /* Current Index Value */ \
228 prefix ## _LVI = off + 5, /* Last Valid Index */ \
229 prefix ## _SR = off + 6, /* Status Register */ \
230 prefix ## _PICB = off + 8, /* Position in Current Buffer */ \
231 prefix ## _PIV = off + 10, /* Prefetched Index Value */ \
232 prefix ## _CR = off + 11 /* Control Register */ \
233 }
234
235#ifndef VBOX_DEVICE_STRUCT_TESTCASE
236typedef enum
237{
238 AC97SOUNDSOURCE_PI_INDEX = 0, /** PCM in */
239 AC97SOUNDSOURCE_PO_INDEX, /** PCM out */
240 AC97SOUNDSOURCE_MC_INDEX, /** Mic in */
241 AC97SOUNDSOURCE_LAST_INDEX
242} AC97SOUNDSOURCE;
243
244AC97_NABMBAR_REGS(PI, AC97SOUNDSOURCE_PI_INDEX * 16);
245AC97_NABMBAR_REGS(PO, AC97SOUNDSOURCE_PO_INDEX * 16);
246AC97_NABMBAR_REGS(MC, AC97SOUNDSOURCE_MC_INDEX * 16);
247#endif
248
249enum
250{
251 /** NABMBAR: Global Control Register. */
252 AC97_GLOB_CNT = 0x2c,
253 /** NABMBAR Global Status. */
254 AC97_GLOB_STA = 0x30,
255 /** Codec Access Semaphore Register. */
256 AC97_CAS = 0x34
257};
258
259#define AC97_PORT2IDX(a_idx) ( ((a_idx) >> 4) & 3 )
260
261
262/*********************************************************************************************************************************
263* Structures and Typedefs *
264*********************************************************************************************************************************/
265
266/**
267 * Buffer Descriptor List Entry (BDLE).
268 */
269typedef struct AC97BDLE
270{
271 uint32_t addr;
272 uint32_t ctl_len;
273} AC97BDLE, *PAC97BDLE;
274
275/**
276 * Bus master register set for an audio stream.
277 */
278typedef struct AC97BMREGS
279{
280 uint32_t bdbar; /** rw 0, Buffer Descriptor List: BAR (Base Address Register). */
281 uint8_t civ; /** ro 0, Current index value. */
282 uint8_t lvi; /** rw 0, Last valid index. */
283 uint16_t sr; /** rw 1, Status register. */
284 uint16_t picb; /** ro 0, Position in current buffer (in samples). */
285 uint8_t piv; /** ro 0, Prefetched index value. */
286 uint8_t cr; /** rw 0, Control register. */
287 int bd_valid; /** Whether current BDLE is initialized or not. */
288 AC97BDLE bd; /** Current Buffer Descriptor List Entry (BDLE). */
289} AC97BMREGS, *PAC97BMREGS;
290
291#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
292/**
293 * Structure keeping the AC'97 stream's state for asynchronous I/O.
294 */
295typedef struct AC97STREAMSTATEAIO
296{
297 /** Thread handle for the actual I/O thread. */
298 RTTHREAD Thread;
299 /** Event for letting the thread know there is some data to process. */
300 RTSEMEVENT Event;
301 /** Critical section for synchronizing access. */
302 RTCRITSECT CritSect;
303 /** Started indicator. */
304 volatile bool fStarted;
305 /** Shutdown indicator. */
306 volatile bool fShutdown;
307 uint32_t Padding1;
308} AC97STREAMSTATEAIO, *PAC97STREAMSTATEAIO;
309#endif
310
311/**
312 * Structure for keeping the internal state of an AC'97 stream.
313 */
314typedef struct AC97STREAMSTATE
315{
316 /** Circular buffer (FIFO) for holding DMA'ed data. */
317 R3PTRTYPE(PRTCIRCBUF) pCircBuf;
318#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
319 /** Asynchronous I/O state members. */
320 AC97STREAMSTATEAIO AIO;
321#endif
322} AC97STREAMSTATE, *PAC97STREAMSTATE;
323
324/**
325 * Structure for an AC'97 stream.
326 */
327typedef struct AC97STREAM
328{
329 /** Stream number (SDn). */
330 uint8_t u8Strm;
331 /** Criticial section for this stream. */
332 RTCRITSECT CritSect;
333 /** Bus master registers of this stream. */
334 AC97BMREGS Regs;
335 /** Internal state of this stream. */
336 AC97STREAMSTATE State;
337} AC97STREAM, *PAC97STREAM;
338
339typedef struct AC97STATE *PAC97STATE;
340#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
341/**
342 * Structure for the async I/O thread context.
343 */
344typedef struct AC97STREAMTHREADCTX
345{
346 PAC97STATE pThis;
347 PAC97STREAM pStream;
348} AC97STREAMTHREADCTX, *PAC97STREAMTHREADCTX;
349#endif
350
351/**
352 * Structure defining a (host backend) driver stream.
353 * Each driver has its own instances of audio mixer streams, which then
354 * can go into the same (or even different) audio mixer sinks.
355 */
356typedef struct AC97DRIVERSTREAM
357{
358 union
359 {
360 /** Desired playback destination (for an output stream). */
361 PDMAUDIOPLAYBACKDEST Dest;
362 /** Desired recording source (for an input stream). */
363 PDMAUDIORECSOURCE Source;
364 } DestSource;
365 uint8_t Padding1[4];
366 /** Associated mixer stream handle. */
367 R3PTRTYPE(PAUDMIXSTREAM) pMixStrm;
368} AC97DRIVERSTREAM, *PAC97DRIVERSTREAM;
369
370/**
371 * Struct for maintaining a host backend driver.
372 */
373typedef struct AC97DRIVER
374{
375 /** Node for storing this driver in our device driver list of AC97STATE. */
376 RTLISTNODER3 Node;
377 /** Pointer to AC97 controller (state). */
378 R3PTRTYPE(PAC97STATE) pAC97State;
379 /** Driver flags. */
380 PDMAUDIODRVFLAGS Flags;
381 uint32_t PaddingFlags;
382 /** LUN # to which this driver has been assigned. */
383 uint8_t uLUN;
384 /** Whether this driver is in an attached state or not. */
385 bool fAttached;
386 uint8_t Padding[4];
387 /** Pointer to attached driver base interface. */
388 R3PTRTYPE(PPDMIBASE) pDrvBase;
389 /** Audio connector interface to the underlying host backend. */
390 R3PTRTYPE(PPDMIAUDIOCONNECTOR) pConnector;
391 /** Driver stream for line input. */
392 AC97DRIVERSTREAM LineIn;
393 /** Driver stream for mic input. */
394 AC97DRIVERSTREAM MicIn;
395 /** Driver stream for output. */
396 AC97DRIVERSTREAM Out;
397} AC97DRIVER, *PAC97DRIVER;
398
399/**
400 * Structure for maintaining an AC'97 device state.
401 */
402typedef struct AC97STATE
403{
404 /** The PCI device state. */
405 PDMPCIDEV PciDev;
406 /** R3 Pointer to the device instance. */
407 PPDMDEVINSR3 pDevInsR3;
408 /** Global Control (Bus Master Control Register). */
409 uint32_t glob_cnt;
410 /** Global Status (Bus Master Control Register). */
411 uint32_t glob_sta;
412 /** Codec Access Semaphore Register (Bus Master Control Register). */
413 uint32_t cas;
414 uint32_t last_samp;
415 uint8_t mixer_data[256];
416 /** AC'97 stream for line-in. */
417 AC97STREAM StreamLineIn;
418 /** AC'97 stream for microphone-in. */
419 AC97STREAM StreamMicIn;
420 /** AC'97 stream for output. */
421 AC97STREAM StreamOut;
422 /** Number of active (running) SDn streams. */
423 uint8_t cStreamsActive;
424#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
425 /** The timer for pumping data thru the attached LUN drivers. */
426 PTMTIMERR3 pTimer;
427 /** Criticial section for timer. */
428 RTCRITSECT csTimer;
429# if HC_ARCH_BITS == 32
430 uint32_t Padding0;
431# endif
432 /** Flag indicating whether the timer is active or not. */
433 bool fTimerActive;
434 uint8_t u8Padding1[7];
435 /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
436 uint64_t cTimerTicks;
437 /** Timestamp of the last timer callback (ac97Timer).
438 * Used to calculate the time actually elapsed between two timer callbacks. */
439 uint64_t uTimerTS;
440#endif
441#ifdef VBOX_WITH_STATISTICS
442 STAMPROFILE StatTimer;
443 STAMPROFILE StatIn;
444 STAMPROFILE StatOut;
445 STAMCOUNTER StatBytesRead;
446 STAMCOUNTER StatBytesWritten;
447#endif
448 /** List of associated LUN drivers (AC97DRIVER). */
449 RTLISTANCHOR lstDrv;
450 /** The device's software mixer. */
451 R3PTRTYPE(PAUDIOMIXER) pMixer;
452 /** Audio sink for PCM output. */
453 R3PTRTYPE(PAUDMIXSINK) pSinkOut;
454 /** Audio sink for line input. */
455 R3PTRTYPE(PAUDMIXSINK) pSinkLineIn;
456 /** Audio sink for microphone input. */
457 R3PTRTYPE(PAUDMIXSINK) pSinkMicIn;
458 uint8_t silence[128];
459 int bup_flag;
460 /** The base interface for LUN\#0. */
461 PDMIBASE IBase;
462 /** Base port of the I/O space region. */
463 RTIOPORT IOPortBase[2];
464 /** Codec model. */
465 uint32_t uCodecModel;
466} AC97STATE, *PAC97STATE;
467
468#ifdef VBOX_WITH_STATISTICS
469AssertCompileMemberAlignment(AC97STATE, StatTimer, 8);
470AssertCompileMemberAlignment(AC97STATE, StatBytesRead, 8);
471AssertCompileMemberAlignment(AC97STATE, StatBytesWritten, 8);
472#endif
473
474#ifndef VBOX_DEVICE_STRUCT_TESTCASE
475
476DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID);
477static int ichac97StreamCreate(PAC97STATE pThis, PAC97STREAM pStream, uint8_t u8Strm);
478static void ichac97StreamDestroy(PAC97STATE pThis, PAC97STREAM pStream);
479static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream);
480static int ichac97StreamReOpen(PAC97STATE pThis, PAC97STREAM pStream);
481static int ichac97StreamClose(PAC97STATE pThis, PAC97STREAM pStream);
482
483static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns);
484#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
485static void ichac97TimerMaybeStart(PAC97STATE pThis);
486static void ichac97TimerMaybeStop(PAC97STATE pThis);
487static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
488#endif
489static int ichac97DoDMA(PAC97STATE pThis, PAC97STREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t cbToProcess, uint32_t *pcbProcessed);
490static void ichac97DoTransfers(PAC97STATE pThis);
491
492#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
493static DECLCALLBACK(int) ichac97StreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser);
494static int ichac97StreamAsyncIONotify(PAC97STATE pThis, PAC97STREAM pStream);
495static void ichac97StreamAsyncIOLock(PAC97STREAM pStream);
496static void ichac97StreamAsyncIOUnlock(PAC97STREAM pStream);
497#endif
498
499static void ichac97WarmReset(PAC97STATE pThis)
500{
501 NOREF(pThis);
502}
503
504static void ichac97ColdReset(PAC97STATE pThis)
505{
506 NOREF(pThis);
507}
508
509DECLINLINE(PAUDMIXSINK) ichac97IndexToSink(PAC97STATE pThis, uint8_t uIndex)
510{
511 AssertPtrReturn(pThis, NULL);
512
513 switch (uIndex)
514 {
515 case AC97SOUNDSOURCE_PI_INDEX: return pThis->pSinkLineIn; break;
516 case AC97SOUNDSOURCE_PO_INDEX: return pThis->pSinkOut; break;
517 case AC97SOUNDSOURCE_MC_INDEX: return pThis->pSinkMicIn; break;
518 default: break;
519 }
520
521 AssertMsgFailed(("Wrong index %RU8\n", uIndex));
522 return NULL;
523}
524
525/** Fetches the buffer descriptor at _CIV. */
526static void ichac97StreamFetchBDLE(PAC97STATE pThis, PAC97STREAM pStream)
527{
528 PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
529 PAC97BMREGS pRegs = &pStream->Regs;
530
531 uint32_t u32[2];
532
533 PDMDevHlpPhysRead(pDevIns, pRegs->bdbar + pRegs->civ * 8, &u32[0], sizeof(u32));
534 pRegs->bd_valid = 1;
535#if !defined(RT_ARCH_X86) && !defined(RT_ARCH_AMD64)
536# error Please adapt the code (audio buffers are little endian)!
537#else
538 pRegs->bd.addr = RT_H2LE_U32(u32[0] & ~3);
539 pRegs->bd.ctl_len = RT_H2LE_U32(u32[1]);
540#endif
541 pRegs->picb = pRegs->bd.ctl_len & AC97_BD_MAX_LEN_MASK;
542 LogFlowFunc(("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
543 pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len >> 16,
544 pRegs->bd.ctl_len & AC97_BD_MAX_LEN_MASK,
545 (pRegs->bd.ctl_len & AC97_BD_MAX_LEN_MASK) << 1)); /** @todo r=andy Assumes 16bit samples. */
546}
547
548/**
549 * Update the BM status register
550 */
551static void ichac97StreamUpdateSR(PAC97STATE pThis, PAC97STREAM pStream, uint32_t new_sr)
552{
553 PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
554 PAC97BMREGS pRegs = &pStream->Regs;
555
556 bool fSignal = false;
557 int iIRQL = 0;
558
559 uint32_t new_mask = new_sr & AC97_SR_INT_MASK;
560 uint32_t old_mask = pRegs->sr & AC97_SR_INT_MASK;
561
562 static uint32_t const masks[] = { AC97_GS_PIINT, AC97_GS_POINT, AC97_GS_MINT };
563
564 if (new_mask ^ old_mask)
565 {
566 /** @todo Is IRQ deasserted when only one of status bits is cleared? */
567 if (!new_mask)
568 {
569 fSignal = true;
570 iIRQL = 0;
571 }
572 else if ((new_mask & AC97_SR_LVBCI) && (pRegs->cr & AC97_CR_LVBIE))
573 {
574 fSignal = true;
575 iIRQL = 1;
576 }
577 else if ((new_mask & AC97_SR_BCIS) && (pRegs->cr & AC97_CR_IOCE))
578 {
579 fSignal = true;
580 iIRQL = 1;
581 }
582 }
583
584 pRegs->sr = new_sr;
585
586 LogFlowFunc(("IOC%d, LVB%d, sr=%#x, fSignal=%RTbool, IRQL=%d\n",
587 pRegs->sr & AC97_SR_BCIS, pRegs->sr & AC97_SR_LVBCI, pRegs->sr, fSignal, iIRQL));
588
589 if (fSignal)
590 {
591 if (iIRQL)
592 pThis->glob_sta |= masks[pStream->u8Strm];
593 else
594 pThis->glob_sta &= ~masks[pStream->u8Strm];
595
596 LogFlowFunc(("Setting IRQ level=%d\n", iIRQL));
597 PDMDevHlpPCISetIrq(pDevIns, 0, iIRQL);
598 }
599}
600
601/**
602 * Returns whether an AC'97 stream is enabled or not.
603 *
604 * @returns IPRT status code.
605 * @param pThis AC'97 device state.
606 * @param pStream Stream to return status for.
607 */
608static bool ichac97StreamIsEnabled(PAC97STATE pThis, PAC97STREAM pStream)
609{
610 AssertPtrReturn(pThis, false);
611 AssertPtrReturn(pStream, false);
612
613 PAUDMIXSINK pSink = ichac97IndexToSink(pThis, pStream->u8Strm);
614 bool fIsEnabled = RT_BOOL(AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING);
615
616 LogFunc(("[SD%RU8] fIsEnabled=%RTbool\n", pStream->u8Strm, fIsEnabled));
617 return fIsEnabled;
618}
619
620static int ichac97StreamEnable(PAC97STATE pThis, PAC97STREAM pStream, bool fEnable)
621{
622 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
623 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
624
625 PAUDMIXSINK pSink = ichac97IndexToSink(pThis, pStream->u8Strm);
626 if (!pSink) /* No sink available (yet)? Bail out early. */
627 return VINF_SUCCESS;
628
629#ifdef LOG_ENABLED
630 const AUDMIXSINKSTS stsSink = AudioMixerSinkGetStatus(pSink);
631
632 const bool fIsEnabled = RT_BOOL(stsSink & AUDMIXSINK_STS_RUNNING);
633 const bool fPendingDisable = RT_BOOL(stsSink & AUDMIXSINK_STS_PENDING_DISABLE);
634
635 LogFunc(("[SD%RU8] fEnable=%RTbool, fIsEnabled=%RTbool, fPendingDisable=%RTbool, DCH=%RTbool, cStreamsActive=%RU8\n",
636 pStream->u8Strm, fEnable, fIsEnabled, fPendingDisable, RT_BOOL(pStream->Regs.sr & AC97_SR_DCH), pThis->cStreamsActive));
637#endif
638
639 int rc = VINF_SUCCESS;
640
641#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
642 ichac97StreamAsyncIOLock(pStream);
643#endif
644
645 if (fEnable)
646 rc = ichac97StreamOpen(pThis, pStream);
647 else
648 rc = ichac97StreamClose(pThis, pStream);
649
650 if (RT_SUCCESS(rc))
651 rc = AudioMixerSinkCtl(ichac97IndexToSink(pThis, pStream->u8Strm),
652 fEnable ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE);
653
654#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
655 ichac97StreamAsyncIOUnlock(pStream);
656#endif
657
658 if (RT_SUCCESS(rc))
659 {
660 if (!fEnable)
661 {
662 if (pThis->cStreamsActive) /* Disable can be called mupltiple times. */
663 pThis->cStreamsActive--;
664
665#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
666 ichac97TimerMaybeStop(pThis);
667#endif
668 }
669 else
670 {
671 pThis->cStreamsActive++;
672#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
673 ichac97TimerMaybeStart(pThis);
674#endif
675 }
676 }
677
678 LogFunc(("Returning %Rrc\n", rc));
679 return rc;
680}
681
682static void ichac97StreamResetBMRegs(PAC97STATE pThis, PAC97STREAM pStream)
683{
684 AssertPtrReturnVoid(pThis);
685 AssertPtrReturnVoid(pStream);
686
687 LogFunc(("[SD%RU8]\n", pStream->u8Strm));
688
689 PAC97BMREGS pRegs = &pStream->Regs;
690
691 pRegs->bdbar = 0;
692 pRegs->civ = 0;
693 pRegs->lvi = 0;
694
695 ichac97StreamEnable(pThis, pStream, false /* fEnable */);
696
697 ichac97StreamUpdateSR(pThis, pStream, AC97_SR_DCH); /** @todo Do we need to do that? */
698
699 pRegs->picb = 0;
700 pRegs->piv = 0;
701 pRegs->cr = pRegs->cr & AC97_CR_DONT_CLEAR_MASK;
702 pRegs->bd_valid = 0;
703
704 RT_ZERO(pThis->silence);
705}
706
707/**
708 * Creates an AC'97 stream.
709 *
710 * @returns IPRT status code.
711 * @param pThis AC'97 state.
712 * @param pStream AC'97 stream to create.
713 * @param u8Strm Stream ID to assign AC'97 stream to.
714 */
715static int ichac97StreamCreate(PAC97STATE pThis, PAC97STREAM pStream, uint8_t u8Strm)
716{
717 AssertPtrReturn(pStream, VERR_INVALID_PARAMETER);
718
719 LogFunc(("[SD%RU8] pStream=%p\n", u8Strm, pStream));
720
721 pStream->u8Strm = u8Strm;
722
723 int rc = RTCritSectInit(&pStream->CritSect);
724 if (RT_SUCCESS(rc))
725 rc = RTCircBufCreate(&pStream->State.pCircBuf, _4K); /** @todo Make this configurable. */
726
727#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
728 /*
729 * Create async I/O stuff.
730 */
731 PAC97STREAMSTATEAIO pAIO = &pStream->State.AIO;
732
733 pAIO->fShutdown = false;
734
735 if (RT_SUCCESS(rc))
736 {
737 rc = RTSemEventCreate(&pAIO->Event);
738 if (RT_SUCCESS(rc))
739 {
740 rc = RTCritSectInit(&pAIO->CritSect);
741 if (RT_SUCCESS(rc))
742 {
743 AC97STREAMTHREADCTX Ctx = { pThis, pStream };
744
745 char szThreadName[64];
746 RTStrPrintf2(szThreadName, sizeof(szThreadName), "ac97AIO%RU8", pStream->u8Strm);
747
748 /** @todo Create threads on demand? */
749
750 rc = RTThreadCreate(&pAIO->Thread, ichac97StreamAsyncIOThread, &Ctx,
751 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, szThreadName);
752 if (RT_SUCCESS(rc))
753 rc = RTThreadUserWait(pAIO->Thread, 10 * 1000 /* 10s timeout */);
754 }
755 }
756 }
757#else
758 RT_NOREF(pThis);
759#endif
760
761 return rc;
762}
763
764/**
765 * Destroys an AC'97 stream.
766 *
767 * @returns IPRT status code.
768 * @param pThis AC'97 state.
769 * @param pStream AC'97 stream to destroy.
770 */
771static void ichac97StreamDestroy(PAC97STATE pThis, PAC97STREAM pStream)
772{
773 LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
774
775 int rc2 = RTCritSectDelete(&pStream->CritSect);
776 AssertRC(rc2);
777
778 if (pStream->State.pCircBuf)
779 {
780 RTCircBufDestroy(pStream->State.pCircBuf);
781 pStream->State.pCircBuf = NULL;
782 }
783
784#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
785 /*
786 * Destroy async I/O stuff.
787 */
788 PAC97STREAMSTATEAIO pAIO = &pStream->State.AIO;
789
790 if (ASMAtomicReadBool(&pAIO->fStarted))
791 {
792 ASMAtomicWriteBool(&pAIO->fShutdown, true);
793
794 rc2 = ichac97StreamAsyncIONotify(pThis, pStream);
795 AssertRC(rc2);
796
797 int rcThread;
798 rc2 = RTThreadWait(pAIO->Thread, 30 * 1000 /* 30s timeout */, &rcThread);
799 LogFunc(("Async I/O thread ended with %Rrc (%Rrc)\n", rc2, rcThread));
800
801 if (RT_SUCCESS(rc2))
802 {
803 rc2 = RTCritSectDelete(&pAIO->CritSect);
804 AssertRC(rc2);
805
806 rc2 = RTSemEventDestroy(pAIO->Event);
807 AssertRC(rc2);
808
809 pAIO->fStarted = false;
810 pAIO->fShutdown = false;
811 }
812 }
813#else
814 RT_NOREF(pThis);
815#endif
816
817 LogFlowFuncLeave();
818}
819
820/**
821 * Creates all AC'97 streams for the device.
822 *
823 * @returns IPRT status code.
824 * @param pThis AC'97 state.
825 */
826static int ichac97StreamsCreate(PAC97STATE pThis)
827{
828 LogFlowFuncEnter();
829
830 /*
831 * Create all sinks and AC'97 streams.
832 */
833
834 /* Line-In. */
835 int rc = AudioMixerCreateSink(pThis->pMixer, "[Recording] Line In", AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
836 if (RT_SUCCESS(rc))
837 rc = ichac97StreamCreate(pThis, &pThis->StreamLineIn, AC97SOUNDSOURCE_PI_INDEX);
838
839 /* Microphone-In. */
840 if (RT_SUCCESS(rc))
841 {
842 rc = AudioMixerCreateSink(pThis->pMixer, "[Recording] Microphone In", AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn);
843 if (RT_SUCCESS(rc))
844 rc = ichac97StreamCreate(pThis, &pThis->StreamMicIn, AC97SOUNDSOURCE_MC_INDEX);
845 }
846
847 /* Output. */
848 if (RT_SUCCESS(rc))
849 {
850 rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOut);
851 if (RT_SUCCESS(rc))
852 rc = ichac97StreamCreate(pThis, &pThis->StreamOut, AC97SOUNDSOURCE_PO_INDEX);
853 }
854
855 /*
856 * Open all streams with the current AC'97 mixer settings.
857 */
858 if (RT_SUCCESS(rc))
859 {
860 rc = ichac97StreamOpen (pThis, &pThis->StreamLineIn);
861 if (RT_SUCCESS(rc))
862 {
863 rc = ichac97StreamOpen (pThis, &pThis->StreamMicIn);
864 if (RT_SUCCESS(rc))
865 {
866 rc = ichac97StreamOpen(pThis, &pThis->StreamOut);
867 }
868 }
869 }
870
871 LogFlowFunc(("Returning %Rrc\n", rc));
872 return rc;
873}
874
875static void ichac97StreamsDestroy(PAC97STATE pThis)
876{
877 LogFlowFuncEnter();
878
879 ichac97StreamDestroy(pThis, &pThis->StreamLineIn);
880 ichac97StreamDestroy(pThis, &pThis->StreamMicIn);
881 ichac97StreamDestroy(pThis, &pThis->StreamOut);
882}
883
884/**
885 * Writes audio data from a mixer sink into an AC'97 stream's DMA buffer.
886 *
887 * @returns IPRT status code.
888 * @param pThis AC'97 state.
889 * @param pStream AC'97 stream to write to.
890 * @param pMixSink Mixer sink to get audio data to write from.
891 * @param cbToWrite Number of bytes to write.
892 * @param pcbWritten Number of bytes written. Optional.
893 */
894static int ichac97StreamWrite(PAC97STATE pThis, PAC97STREAM pDstStream, PAUDMIXSINK pSrcMixSink, uint32_t cbToWrite,
895 uint32_t *pcbWritten)
896{
897 RT_NOREF(pThis);
898
899 PRTCIRCBUF pCircBuf = pDstStream->State.pCircBuf;
900 AssertPtr(pCircBuf);
901
902 void *pvDst;
903 size_t cbDst;
904
905 uint32_t cbRead = 0;
906
907 RTCircBufAcquireWriteBlock(pCircBuf, cbToWrite, &pvDst, &cbDst);
908
909 if (cbDst)
910 {
911 int rc2 = AudioMixerSinkRead(pSrcMixSink, AUDMIXOP_COPY, pvDst, (uint32_t)cbDst, &cbRead);
912 AssertRC(rc2);
913
914#ifdef AC97_DEBUG_DUMP_PCM_DATA
915 RTFILE fh;
916 RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ichac97StreamWrite.pcm",
917 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
918 RTFileWrite(fh, pvDst, cbRead, NULL);
919 RTFileClose(fh);
920#endif
921 }
922
923 RTCircBufReleaseWriteBlock(pCircBuf, cbRead);
924
925 if (pcbWritten)
926 *pcbWritten = cbRead;
927
928 return VINF_SUCCESS;
929}
930
931/**
932 * Reads audio data from an AC'97 stream's DMA buffer and writes into a specified mixer sink.
933 *
934 * @returns IPRT status code.
935 * @param pThis AC'97 state.
936 * @param pSrcStream AC'97 stream to read audio data from.
937 * @param pDstMixSink Mixer sink to write audio data to.
938 * @param cbToRead Number of bytes to read.
939 * @param pcbRead Number of bytes read. Optional.
940 */
941static int ichac97StreamRead(PAC97STATE pThis, PAC97STREAM pSrcStream, PAUDMIXSINK pDstMixSink, uint32_t cbToRead,
942 uint32_t *pcbRead)
943{
944 RT_NOREF(pThis);
945
946 PRTCIRCBUF pCircBuf = pSrcStream->State.pCircBuf;
947 AssertPtr(pCircBuf);
948
949 void *pvSrc;
950 size_t cbSrc;
951
952 uint32_t cbWritten = 0;
953
954 RTCircBufAcquireReadBlock(pCircBuf, cbToRead, &pvSrc, &cbSrc);
955
956 if (cbSrc)
957 {
958#ifdef AC97_DEBUG_DUMP_PCM_DATA
959 RTFILE fh;
960 RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97StreamRead.pcm",
961 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
962 RTFileWrite(fh, pvSrc, cbSrc, NULL);
963 RTFileClose(fh);
964#endif
965 int rc2 = AudioMixerSinkWrite(pDstMixSink, AUDMIXOP_COPY, pvSrc, (uint32_t)cbSrc, &cbWritten);
966 AssertRC(rc2);
967 }
968
969 RTCircBufReleaseReadBlock(pCircBuf, cbWritten);
970
971 if (pcbRead)
972 *pcbRead = cbWritten;
973
974 return VINF_SUCCESS;
975}
976
977#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
978/**
979 * Asynchronous I/O thread for an AC'97 stream.
980 * This will do the heavy lifting work for us as soon as it's getting notified by another thread.
981 *
982 * @returns IPRT status code.
983 * @param hThreadSelf Thread handle.
984 * @param pvUser User argument. Must be of type PAC97STREAMTHREADCTX.
985 */
986static DECLCALLBACK(int) ichac97StreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser)
987{
988 PAC97STREAMTHREADCTX pCtx = (PAC97STREAMTHREADCTX)pvUser;
989 AssertPtr(pCtx);
990
991 PAC97STATE pThis = pCtx->pThis;
992 AssertPtr(pThis);
993
994 PAC97STREAM pStream = pCtx->pStream;
995 AssertPtr(pStream);
996
997 PAC97STREAMSTATEAIO pAIO = &pCtx->pStream->State.AIO;
998
999 PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
1000 AssertPtr(pCircBuf);
1001
1002 PAUDMIXSINK pMixSink = ichac97IndexToSink(pThis, pStream->u8Strm);
1003 AssertPtr(pMixSink);
1004
1005 ASMAtomicXchgBool(&pAIO->fStarted, true);
1006
1007 RTThreadUserSignal(hThreadSelf);
1008
1009 LogFunc(("[SD%RU8]: Started\n", pStream->u8Strm));
1010
1011 for (;;)
1012 {
1013 Log2Func(("[SD%RU8]: Waiting ...\n", pStream->u8Strm));
1014
1015 int rc2 = RTSemEventWait(pAIO->Event, RT_INDEFINITE_WAIT);
1016 if (RT_FAILURE(rc2))
1017 break;
1018
1019 if (ASMAtomicReadBool(&pAIO->fShutdown))
1020 break;
1021
1022 size_t cbToProcess = RTCircBufUsed(pCircBuf);
1023 if (cbToProcess)
1024 {
1025 uint32_t cbProcessed = 0;
1026
1027 rc2 = RTCritSectEnter(&pAIO->CritSect);
1028 if (RT_SUCCESS(rc2))
1029 {
1030 switch (pStream->u8Strm)
1031 {
1032 case AC97SOUNDSOURCE_PI_INDEX:
1033 case AC97SOUNDSOURCE_MC_INDEX:
1034 rc2 = ichac97StreamWrite(pThis, pStream, pMixSink, (uint32_t)cbToProcess, &cbProcessed);
1035 break;
1036
1037 case AC97SOUNDSOURCE_PO_INDEX:
1038 rc2 = ichac97StreamRead(pThis, pStream, pMixSink, (uint32_t)cbToProcess, &cbProcessed);
1039 break;
1040
1041 default:
1042 AssertFailedStmt(rc2 = VERR_NOT_SUPPORTED);
1043 break;
1044 }
1045
1046 if (RT_SUCCESS(rc2))
1047 rc2 = AudioMixerSinkUpdate(pMixSink);
1048
1049 if (cbProcessed)
1050 {
1051 Assert(cbToProcess >= cbProcessed);
1052 cbToProcess -= cbProcessed;
1053 }
1054
1055 int rc3 = RTCritSectLeave(&pAIO->CritSect);
1056 AssertRC(rc3);
1057 }
1058 }
1059
1060 AssertRC(rc2);
1061 }
1062
1063 LogFunc(("[SD%RU8]: Ended\n", pStream->u8Strm));
1064
1065 ASMAtomicXchgBool(&pAIO->fStarted, false);
1066
1067 return VINF_SUCCESS;
1068}
1069
1070/**
1071 * Lets the stream's async I/O thread know that there is some data to process.
1072 *
1073 * @returns IPRT status code.
1074 * @param pThis AC'97 state.
1075 * @param pStream AC'97 stream to notify async I/O thread for.
1076 */
1077static int ichac97StreamAsyncIONotify(PAC97STATE pThis, PAC97STREAM pStream)
1078{
1079 RT_NOREF(pThis);
1080
1081 LogFunc(("[SD%RU8]\n", pStream->u8Strm));
1082 return RTSemEventSignal(pStream->State.AIO.Event);
1083}
1084
1085static void ichac97StreamAsyncIOLock(PAC97STREAM pStream)
1086{
1087 PAC97STREAMSTATEAIO pAIO = &pStream->State.AIO;
1088
1089 int rc2 = RTCritSectEnter(&pAIO->CritSect);
1090 AssertRC(rc2);
1091}
1092
1093static void ichac97StreamAsyncIOUnlock(PAC97STREAM pStream)
1094{
1095 PAC97STREAMSTATEAIO pAIO = &pStream->State.AIO;
1096
1097 int rc2 = RTCritSectLeave(&pAIO->CritSect);
1098 AssertRC(rc2);
1099}
1100#endif /* VBOX_WITH_AUDIO_AC97_ASYNC_IO*/
1101
1102/**
1103 * Updates an AC'97 stream according to its usage (input / output).
1104 *
1105 * For an SDO (output) stream this means reading DMA data from the device to
1106 * the connected audio sink(s).
1107 *
1108 * For an SDI (input) stream this is reading audio data from the connected
1109 * audio sink(s) and writing it as DMA data to the device.
1110 *
1111 * @returns IPRT status code.
1112 * @param pThis AC'97 state.
1113 * @param pStream AC'97 stream to update.
1114 */
1115static int ichac97StreamUpdate(PAC97STATE pThis, PAC97STREAM pStream)
1116{
1117 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1118 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
1119
1120 PAUDMIXSINK pMixSink = ichac97IndexToSink(pThis, pStream->u8Strm);
1121 if (!pMixSink)
1122 return VINF_SUCCESS;
1123
1124 if (AudioMixerSinkIsActive(pMixSink) == false)
1125 return VINF_SUCCESS;
1126
1127 PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
1128 AssertPtr(pCircBuf);
1129
1130 int rc = VINF_SUCCESS;
1131
1132 bool fDone = false;
1133
1134 LogFunc(("[SD%RU8] Started\n", pStream->u8Strm));
1135
1136 while (!fDone)
1137 {
1138 int rc2;
1139 uint32_t cbProcessed = 0;
1140
1141 if (pStream->u8Strm == AC97SOUNDSOURCE_PO_INDEX) /* Output. */
1142 {
1143 STAM_PROFILE_START(&pThis->StatOut, a);
1144
1145 void *pvDst;
1146 size_t cbDst;
1147
1148 RTCircBufAcquireWriteBlock(pCircBuf, 256 /** @todo */, &pvDst, &cbDst);
1149
1150 if (cbDst)
1151 {
1152 /* Do one DMA transfer with FIFOS size at a time. */
1153 rc2 = ichac97DoDMA(pThis, pStream, pvDst, (uint32_t)cbDst, (uint32_t)cbDst /* cbToProcess */, &cbProcessed);
1154 AssertRC(rc2);
1155 }
1156
1157 RTCircBufReleaseWriteBlock(pCircBuf, cbProcessed);
1158
1159 if (cbProcessed)
1160 {
1161#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
1162 /* Let the asynchronous thread know that there is some new data to process. */
1163 ichac97StreamAsyncIONotify(pThis, pStream);
1164#else
1165 rc2 = ichac97StreamRead(pThis, pStream, pMixSink, cbProcessed, NULL /* pcbRead */);
1166 AssertRC(rc2);
1167#endif
1168 }
1169
1170 if ( !cbProcessed
1171#ifndef VBOX_WITH_AUDIO_AC97_ASYNC_IO
1172 && RTCircBufUsed(pCircBuf) == 0
1173#endif
1174 )
1175 {
1176 fDone = true;
1177 }
1178
1179 STAM_PROFILE_STOP(&pThis->StatOut, a);
1180 }
1181 else if ( pStream->u8Strm == AC97SOUNDSOURCE_PI_INDEX /* Input. */
1182 || pStream->u8Strm == AC97SOUNDSOURCE_MC_INDEX) /* Input. */
1183 {
1184 STAM_PROFILE_START(&pThis->StatIn, a);
1185
1186 void *pvSrc;
1187 size_t cbSrc;
1188
1189 RTCircBufAcquireReadBlock(pCircBuf, 256 /** @todo */, &pvSrc, &cbSrc);
1190
1191 if (cbSrc)
1192 {
1193 /* Do one DMA transfer with FIFOS size at a time. */
1194 rc2 = ichac97DoDMA(pThis, pStream, pvSrc, (uint32_t)cbSrc, (uint32_t)cbSrc /* cbToProcess */, &cbProcessed);
1195 AssertRC(rc2);
1196 }
1197
1198 RTCircBufReleaseReadBlock(pCircBuf, cbProcessed);
1199
1200 if (cbProcessed)
1201 {
1202#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
1203 /* Let the asynchronous thread know that there is some new data to process. */
1204 ichac97StreamAsyncIONotify(pThis, pStream);
1205#else
1206 rc2 = ichac97StreamWrite(pThis, pStream, pMixSink, cbProcessed, NULL /* pcbWritten */);
1207 AssertRC(rc2);
1208#endif
1209 }
1210
1211 STAM_PROFILE_STOP(&pThis->StatIn, a);
1212 }
1213 else
1214 AssertFailed();
1215
1216#ifndef VBOX_WITH_AUDIO_AC97_ASYNC_IO
1217 rc2 = AudioMixerSinkUpdate(pMixSink);
1218 AssertRC(rc2);
1219#endif
1220 if (fDone)
1221 break;
1222 }
1223
1224 LogFunc(("[SD%RU8] End\n", pStream->u8Strm));
1225
1226 return rc;
1227}
1228
1229static void ichac97MixerSet(PAC97STATE pThis, uint8_t uMixerIdx, uint16_t uVal)
1230{
1231 if (size_t(uMixerIdx + 2) > sizeof(pThis->mixer_data))
1232 {
1233 AssertMsgFailed(("Index %RU8 out of bounds(%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)));
1234 return;
1235 }
1236
1237 pThis->mixer_data[uMixerIdx + 0] = RT_LO_U8(uVal);
1238 pThis->mixer_data[uMixerIdx + 1] = RT_HI_U8(uVal);
1239}
1240
1241static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t uMixerIdx)
1242{
1243 uint16_t uVal;
1244
1245 if (size_t(uMixerIdx + 2) > sizeof(pThis->mixer_data))
1246 {
1247 AssertMsgFailed(("Index %RU8 out of bounds (%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)));
1248 uVal = UINT16_MAX;
1249 }
1250 else
1251 uVal = RT_MAKE_U16(pThis->mixer_data[uMixerIdx + 0], pThis->mixer_data[uMixerIdx + 1]);
1252
1253 return uVal;
1254}
1255
1256/**
1257 * Retrieves a specific driver stream of a AC'97 driver.
1258 *
1259 * @returns Pointer to driver stream if found, or NULL if not found.
1260 * @param pThis AC'97 state.
1261 * @param pDrv Driver to retrieve driver stream for.
1262 * @param enmDir Stream direction to retrieve.
1263 * @param dstSrc Stream destination / source to retrieve.
1264 */
1265static PAC97DRIVERSTREAM ichac97MixerGetDrvStream(PAC97STATE pThis, PAC97DRIVER pDrv,
1266 PDMAUDIODIR enmDir, PDMAUDIODESTSOURCE dstSrc)
1267{
1268 RT_NOREF(pThis);
1269
1270 PAC97DRIVERSTREAM pDrvStream = NULL;
1271
1272 if (enmDir == PDMAUDIODIR_IN)
1273 {
1274 LogFunc(("enmRecSource=%d\n", dstSrc.Source));
1275
1276 switch (dstSrc.Source)
1277 {
1278 case PDMAUDIORECSOURCE_LINE:
1279 pDrvStream = &pDrv->LineIn;
1280 break;
1281 case PDMAUDIORECSOURCE_MIC:
1282 pDrvStream = &pDrv->MicIn;
1283 break;
1284 default:
1285 AssertFailed();
1286 break;
1287 }
1288 }
1289 else if (enmDir == PDMAUDIODIR_OUT)
1290 {
1291 LogFunc(("enmPlaybackDest=%d\n", dstSrc.Dest));
1292
1293 switch (dstSrc.Dest)
1294 {
1295 case PDMAUDIOPLAYBACKDEST_FRONT:
1296 pDrvStream = &pDrv->Out;
1297 break;
1298 default:
1299 AssertFailed();
1300 break;
1301 }
1302 }
1303 else
1304 AssertFailed();
1305
1306 return pDrvStream;
1307}
1308
1309/**
1310 * Adds audio streams for all drivers to a specific mixer sink.
1311 *
1312 * @returns IPRT status code.
1313 * @param pThis AC'97 state.
1314 * @param pMixSink Mixer sink to add stream to.
1315 * @param pCfg Stream configuration to use.
1316 */
1317static int ichac97MixerAddDrvStreams(PAC97STATE pThis, PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg)
1318{
1319 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1320 AssertPtrReturn(pMixSink, VERR_INVALID_POINTER);
1321 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1322
1323 /* Update the sink's format. */
1324 PDMAUDIOPCMPROPS PCMProps;
1325 int rc = DrvAudioHlpStreamCfgToProps(pCfg, &PCMProps);
1326 if (RT_SUCCESS(rc))
1327 rc = AudioMixerSinkSetFormat(pMixSink, &PCMProps);
1328
1329 if (RT_FAILURE(rc))
1330 return rc;
1331
1332 PAC97DRIVER pDrv;
1333 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
1334 {
1335 PPDMAUDIOSTREAMCFG pStreamCfg = (PPDMAUDIOSTREAMCFG)RTMemDup(pCfg, sizeof(PDMAUDIOSTREAMCFG));
1336 if (!pStreamCfg)
1337 {
1338 rc = VERR_NO_MEMORY;
1339 break;
1340 }
1341
1342 if (!RTStrPrintf(pStreamCfg->szName, sizeof(pStreamCfg->szName), "[LUN#%RU8] %s", pDrv->uLUN, pCfg->szName))
1343 {
1344 RTMemFree(pStreamCfg);
1345
1346 rc = VERR_BUFFER_OVERFLOW;
1347 break;
1348 }
1349
1350 LogFunc(("%s\n", pStreamCfg->szName));
1351
1352 int rc2 = VINF_SUCCESS;
1353
1354 PAC97DRIVERSTREAM pDrvStream = ichac97MixerGetDrvStream(pThis, pDrv, pStreamCfg->enmDir, pStreamCfg->DestSource);
1355 if (pDrvStream)
1356 {
1357 AssertMsg(pDrvStream->pMixStrm == NULL, ("[LUN#%RU8] Driver stream already present when it must not\n", pDrv->uLUN));
1358
1359 PAUDMIXSTREAM pMixStrm;
1360 rc2 = AudioMixerSinkCreateStream(pMixSink, pDrv->pConnector, pStreamCfg, 0 /* fFlags */, &pMixStrm);
1361 if (RT_SUCCESS(rc2))
1362 {
1363 rc2 = AudioMixerSinkAddStream(pMixSink, pMixStrm);
1364 LogFlowFunc(("LUN#%RU8: Created stream \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2));
1365 }
1366
1367 if (RT_SUCCESS(rc2))
1368 pDrvStream->pMixStrm = pMixStrm;
1369 }
1370
1371 if (RT_SUCCESS(rc))
1372 rc = rc2;
1373
1374 if (pStreamCfg)
1375 {
1376 RTMemFree(pStreamCfg);
1377 pStreamCfg = NULL;
1378 }
1379 }
1380
1381 LogFlowFuncLeaveRC(rc);
1382 return rc;
1383}
1384
1385/**
1386 * Removes specific audio streams for all drivers.
1387 *
1388 * @param pThis AC'97 state.
1389 * @param pMixSink Mixer sink to remove audio streams from.
1390 * @param enmDir Stream direction to remove.
1391 * @param dstSrc Stream destination / source to remove.
1392 */
1393static void ichac97MixerRemoveDrvStreams(PAC97STATE pThis, PAUDMIXSINK pMixSink,
1394 PDMAUDIODIR enmDir, PDMAUDIODESTSOURCE dstSrc)
1395{
1396 AssertPtrReturnVoid(pThis);
1397 AssertPtrReturnVoid(pMixSink);
1398
1399 PAC97DRIVER pDrv;
1400 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
1401 {
1402 PAC97DRIVERSTREAM pDrvStream = ichac97MixerGetDrvStream(pThis, pDrv, enmDir, dstSrc);
1403 if (pDrvStream)
1404 {
1405 if (pDrvStream->pMixStrm)
1406 {
1407 AudioMixerSinkRemoveStream(pMixSink, pDrvStream->pMixStrm);
1408
1409 AudioMixerStreamDestroy(pDrvStream->pMixStrm);
1410 pDrvStream->pMixStrm = NULL;
1411 }
1412 }
1413 }
1414}
1415
1416/**
1417 * Opens an AC'97 stream with its current mixer settings.
1418 *
1419 * This will open an AC'97 stream with 2 (stereo) channels, 16-bit samples and
1420 * the last set sample rate in the AC'97 mixer for this stream.
1421 *
1422 * @returns IPRT status code.
1423 * @param pThis AC'97 state.
1424 * @param pStream AC'97 Stream to open.
1425 */
1426static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream)
1427{
1428 int rc = VINF_SUCCESS;
1429
1430 LogFunc(("[SD%RU8]\n", pStream->u8Strm));
1431
1432 PDMAUDIOSTREAMCFG streamCfg;
1433 RT_ZERO(streamCfg);
1434
1435 PAUDMIXSINK pMixSink = NULL;
1436
1437 switch (pStream->u8Strm)
1438 {
1439 case AC97SOUNDSOURCE_PI_INDEX:
1440 {
1441 streamCfg.uHz = ichac97MixerGet(pThis, AC97_PCM_LR_ADC_Rate);
1442 streamCfg.enmDir = PDMAUDIODIR_IN;
1443 streamCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
1444
1445 RTStrPrintf2(streamCfg.szName, sizeof(streamCfg.szName), "Line-In");
1446
1447 pMixSink = pThis->pSinkLineIn;
1448 break;
1449 }
1450
1451 case AC97SOUNDSOURCE_MC_INDEX:
1452 {
1453 streamCfg.uHz = ichac97MixerGet(pThis, AC97_MIC_ADC_Rate);
1454 streamCfg.enmDir = PDMAUDIODIR_IN;
1455 streamCfg.DestSource.Source = PDMAUDIORECSOURCE_MIC;
1456
1457 RTStrPrintf2(streamCfg.szName, sizeof(streamCfg.szName), "Mic-In");
1458
1459 pMixSink = pThis->pSinkMicIn;
1460 break;
1461 }
1462
1463 case AC97SOUNDSOURCE_PO_INDEX:
1464 {
1465 streamCfg.uHz = ichac97MixerGet(pThis, AC97_PCM_Front_DAC_Rate);
1466 streamCfg.enmDir = PDMAUDIODIR_OUT;
1467 streamCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
1468
1469 RTStrPrintf2(streamCfg.szName, sizeof(streamCfg.szName), "Output");
1470
1471 pMixSink = pThis->pSinkOut;
1472 break;
1473 }
1474
1475 default:
1476 rc = VERR_NOT_SUPPORTED;
1477 break;
1478 }
1479
1480 if (RT_SUCCESS(rc))
1481 {
1482 if (streamCfg.uHz) /* Some valid rate set in the AC'97 mixer? */
1483 {
1484 streamCfg.cChannels = 2;
1485 streamCfg.enmFormat = PDMAUDIOFMT_S16;
1486 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
1487
1488 ichac97MixerRemoveDrvStreams(pThis, pMixSink, streamCfg.enmDir, streamCfg.DestSource);
1489
1490 rc = ichac97MixerAddDrvStreams(pThis, pMixSink, &streamCfg);
1491 }
1492 }
1493
1494 LogFlowFunc(("[SD%RU8] rc=%Rrc\n", pStream->u8Strm, rc));
1495 return rc;
1496}
1497
1498/**
1499 * Closes an AC'97 stream.
1500 *
1501 * @returns IPRT status code.
1502 * @param pThis AC'97 state.
1503 * @param pStream AC'97 stream to close.
1504 */
1505static int ichac97StreamClose(PAC97STATE pThis, PAC97STREAM pStream)
1506{
1507 RT_NOREF(pThis);
1508 RT_NOREF(pStream);
1509
1510 LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
1511
1512 return VINF_SUCCESS;
1513}
1514
1515/**
1516 * Re-opens (that is, closes and opens again) an AC'97 stream on the backend
1517 * side with the current AC'97 mixer settings for this stream.
1518 *
1519 * @returns IPRT status code.
1520 * @param pThis AC'97 device state.
1521 * @param pStream AC'97 stream to re-open.
1522 */
1523static int ichac97StreamReOpen(PAC97STATE pThis, PAC97STREAM pStream)
1524{
1525 LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
1526
1527 int rc = ichac97StreamClose(pThis, pStream);
1528 if (RT_SUCCESS(rc))
1529 rc = ichac97StreamOpen(pThis, pStream);
1530
1531 return rc;
1532}
1533
1534/**
1535 * Resets an AC'97 stream.
1536 *
1537 * @returns IPRT status code.
1538 * @param pThis AC'97 state.
1539 * @param pStream AC'97 stream to reset.
1540 * @remark
1541 */
1542static void ichac97StreamReset(PAC97STATE pThis, PAC97STREAM pStream)
1543{
1544 AssertPtrReturnVoid(pThis);
1545 AssertPtrReturnVoid(pStream);
1546
1547 LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
1548
1549 if (pStream->State.pCircBuf)
1550 RTCircBufReset(pStream->State.pCircBuf);
1551}
1552
1553static int ichac97MixerSetVolume(PAC97STATE pThis, int index, PDMAUDIOMIXERCTL enmMixerCtl, uint32_t uVal)
1554{
1555 bool fCntlMuted;
1556 uint8_t lCntlAtt, rCntlAtt;
1557
1558 /*
1559 * From AC'97 SoundMax Codec AD1981A/AD1981B:
1560 * "Because AC '97 defines 6-bit volume registers, to maintain compatibility whenever the
1561 * D5 or D13 bits are set to 1, their respective lower five volume bits are automatically
1562 * set to 1 by the Codec logic. On readback, all lower 5 bits will read ones whenever
1563 * these bits are set to 1."
1564 *
1565 * Linux ALSA depends on this behavior.
1566 */
1567 /// @todo Does this apply to anything other than the master volume control?
1568 if (uVal & RT_BIT(5))
1569 uVal |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
1570 if (uVal & RT_BIT(13))
1571 uVal |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
1572
1573 fCntlMuted = (uVal >> AC97_BARS_VOL_MUTE_SHIFT) & 1;
1574 lCntlAtt = (uVal >> 8) & AC97_BARS_VOL_MASK;
1575 rCntlAtt = uVal & AC97_BARS_VOL_MASK;
1576
1577 /* For the master and headphone volume, 0 corresponds to 0dB attenuation. For the other
1578 * volume controls, 0 means 12dB gain and 8 means unity gain.
1579 */
1580 if (index != AC97_Master_Volume_Mute && index != AC97_Headphone_Volume_Mute)
1581 {
1582#ifndef VBOX_WITH_AC97_GAIN_SUPPORT
1583 /* NB: Currently there is no gain support, only attenuation. */
1584 lCntlAtt = lCntlAtt < 8 ? 0 : lCntlAtt - 8;
1585 rCntlAtt = rCntlAtt < 8 ? 0 : rCntlAtt - 8;
1586#endif
1587 }
1588 Assert(lCntlAtt <= 255 / AC97_DB_FACTOR);
1589 Assert(rCntlAtt <= 255 / AC97_DB_FACTOR);
1590
1591 LogFunc(("index=0x%x, uVal=%RU32, enmMixerCtl=%RU32\n", index, uVal, enmMixerCtl));
1592 LogFunc(("lAtt=%RU8, rAtt=%RU8 ", lCntlAtt, rCntlAtt));
1593
1594 /*
1595 * For AC'97 volume controls, each additional step means -1.5dB attenuation with
1596 * zero being maximum. In contrast, we're internally using 255 (PDMAUDIO_VOLUME_MAX)
1597 * steps, each -0.375dB, where 0 corresponds to -96dB and 255 corresponds to 0dB.
1598 */
1599 uint8_t lVol = PDMAUDIO_VOLUME_MAX - lCntlAtt * AC97_DB_FACTOR;
1600 uint8_t rVol = PDMAUDIO_VOLUME_MAX - rCntlAtt * AC97_DB_FACTOR;
1601
1602 Log(("-> fMuted=%RTbool, lVol=%RU8, rVol=%RU8\n", fCntlMuted, lVol, rVol));
1603
1604 int rc = VINF_SUCCESS;
1605
1606 if (pThis->pMixer) /* Device can be in reset state, so no mixer available. */
1607 {
1608 PDMAUDIOVOLUME Vol = { fCntlMuted, lVol, rVol };
1609 PAUDMIXSINK pSink = NULL;
1610
1611 switch (enmMixerCtl)
1612 {
1613 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
1614 rc = AudioMixerSetMasterVolume(pThis->pMixer, &Vol);
1615 break;
1616
1617 case PDMAUDIOMIXERCTL_FRONT:
1618 pSink = pThis->pSinkOut;
1619 break;
1620
1621 case PDMAUDIOMIXERCTL_MIC_IN:
1622 pSink = pThis->pSinkMicIn;
1623 break;
1624
1625 case PDMAUDIOMIXERCTL_LINE_IN:
1626 pSink = pThis->pSinkLineIn;
1627 break;
1628
1629 default:
1630 AssertFailed();
1631 rc = VERR_NOT_SUPPORTED;
1632 break;
1633 }
1634
1635 if (pSink)
1636 rc = AudioMixerSinkSetVolume(pSink, &Vol);
1637 }
1638
1639 ichac97MixerSet(pThis, index, uVal);
1640
1641 if (RT_FAILURE(rc))
1642 LogFlowFunc(("Failed with %Rrc\n", rc));
1643
1644 return rc;
1645}
1646
1647static PDMAUDIORECSOURCE ichac97IndextoRecSource(uint8_t i)
1648{
1649 switch (i)
1650 {
1651 case AC97_REC_MIC: return PDMAUDIORECSOURCE_MIC;
1652 case AC97_REC_CD: return PDMAUDIORECSOURCE_CD;
1653 case AC97_REC_VIDEO: return PDMAUDIORECSOURCE_VIDEO;
1654 case AC97_REC_AUX: return PDMAUDIORECSOURCE_AUX;
1655 case AC97_REC_LINE_IN: return PDMAUDIORECSOURCE_LINE;
1656 case AC97_REC_PHONE: return PDMAUDIORECSOURCE_PHONE;
1657 default:
1658 break;
1659 }
1660
1661 LogFlowFunc(("Unknown record source %d, using MIC\n", i));
1662 return PDMAUDIORECSOURCE_MIC;
1663}
1664
1665static uint8_t ichac97RecSourceToIndex(PDMAUDIORECSOURCE rs)
1666{
1667 switch (rs)
1668 {
1669 case PDMAUDIORECSOURCE_MIC: return AC97_REC_MIC;
1670 case PDMAUDIORECSOURCE_CD: return AC97_REC_CD;
1671 case PDMAUDIORECSOURCE_VIDEO: return AC97_REC_VIDEO;
1672 case PDMAUDIORECSOURCE_AUX: return AC97_REC_AUX;
1673 case PDMAUDIORECSOURCE_LINE: return AC97_REC_LINE_IN;
1674 case PDMAUDIORECSOURCE_PHONE: return AC97_REC_PHONE;
1675 default:
1676 break;
1677 }
1678
1679 LogFlowFunc(("Unknown audio recording source %d using MIC\n", rs));
1680 return AC97_REC_MIC;
1681}
1682
1683static void ichac97RecordSelect(PAC97STATE pThis, uint32_t val)
1684{
1685 uint8_t rs = val & AC97_REC_MASK;
1686 uint8_t ls = (val >> 8) & AC97_REC_MASK;
1687 PDMAUDIORECSOURCE ars = ichac97IndextoRecSource(rs);
1688 PDMAUDIORECSOURCE als = ichac97IndextoRecSource(ls);
1689 rs = ichac97RecSourceToIndex(ars);
1690 ls = ichac97RecSourceToIndex(als);
1691 ichac97MixerSet(pThis, AC97_Record_Select, rs | (ls << 8));
1692}
1693
1694static int ichac97MixerReset(PAC97STATE pThis)
1695{
1696 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
1697
1698 LogFlowFuncEnter();
1699
1700 RT_ZERO(pThis->mixer_data);
1701
1702 /* Note: Make sure to reset all registers first before bailing out on error. */
1703
1704 ichac97MixerSet(pThis, AC97_Reset , 0x0000); /* 6940 */
1705 ichac97MixerSet(pThis, AC97_Master_Volume_Mono_Mute , 0x8000);
1706 ichac97MixerSet(pThis, AC97_PC_BEEP_Volume_Mute , 0x0000);
1707
1708 ichac97MixerSet(pThis, AC97_Phone_Volume_Mute , 0x8008);
1709 ichac97MixerSet(pThis, AC97_Mic_Volume_Mute , 0x8008);
1710 ichac97MixerSet(pThis, AC97_CD_Volume_Mute , 0x8808);
1711 ichac97MixerSet(pThis, AC97_Aux_Volume_Mute , 0x8808);
1712 ichac97MixerSet(pThis, AC97_Record_Gain_Mic_Mute , 0x8000);
1713 ichac97MixerSet(pThis, AC97_General_Purpose , 0x0000);
1714 ichac97MixerSet(pThis, AC97_3D_Control , 0x0000);
1715 ichac97MixerSet(pThis, AC97_Powerdown_Ctrl_Stat , 0x000f);
1716
1717 ichac97MixerSet(pThis, AC97_Extended_Audio_ID , 0x0809);
1718 ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, 0x0009);
1719 ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate , 0xbb80);
1720 ichac97MixerSet(pThis, AC97_PCM_Surround_DAC_Rate , 0xbb80);
1721 ichac97MixerSet(pThis, AC97_PCM_LFE_DAC_Rate , 0xbb80);
1722 ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate , 0xbb80);
1723 ichac97MixerSet(pThis, AC97_MIC_ADC_Rate , 0xbb80);
1724
1725 if (pThis->uCodecModel == AC97_CODEC_AD1980)
1726 {
1727 /* Analog Devices 1980 (AD1980) */
1728 ichac97MixerSet(pThis, AC97_Reset , 0x0010); /* Headphones. */
1729 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144);
1730 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5370);
1731 ichac97MixerSet(pThis, AC97_Headphone_Volume_Mute , 0x8000);
1732 }
1733 else if (pThis->uCodecModel == AC97_CODEC_AD1981B)
1734 {
1735 /* Analog Devices 1981B (AD1981B) */
1736 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144);
1737 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5374);
1738 }
1739 else
1740 {
1741 /* Sigmatel 9700 (STAC9700) */
1742 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x8384);
1743 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x7600); /* 7608 */
1744 }
1745 ichac97RecordSelect(pThis, 0);
1746
1747 ichac97MixerSetVolume(pThis, AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER, 0x8000);
1748 ichac97MixerSetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT, 0x8808);
1749 ichac97MixerSetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808);
1750 ichac97MixerSetVolume(pThis, AC97_Mic_Volume_Mute, PDMAUDIOMIXERCTL_MIC_IN, 0x8808);
1751
1752 return VINF_SUCCESS;
1753}
1754
1755static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
1756{
1757return;
1758
1759 LogFlowFunc(("cbElapsed=%RU32\n", cbElapsed));
1760
1761 if (!(pThis->bup_flag & BUP_SET))
1762 {
1763 if (pThis->bup_flag & BUP_LAST)
1764 {
1765 unsigned int i;
1766 uint32_t *p = (uint32_t*)pThis->silence;
1767 for (i = 0; i < sizeof(pThis->silence) / 4; i++) /** @todo r=andy Assumes 16-bit samples, stereo. */
1768 *p++ = pThis->last_samp;
1769 }
1770 else
1771 RT_ZERO(pThis->silence);
1772
1773 pThis->bup_flag |= BUP_SET;
1774 }
1775
1776 while (cbElapsed)
1777 {
1778 uint32_t cbToWrite = RT_MIN(cbElapsed, (uint32_t)sizeof(pThis->silence));
1779 uint32_t cbWrittenToStream;
1780
1781 int rc2 = AudioMixerSinkWrite(pThis->pSinkOut, AUDMIXOP_COPY,
1782 pThis->silence, cbToWrite, &cbWrittenToStream);
1783 if (RT_SUCCESS(rc2))
1784 {
1785 if (cbWrittenToStream < cbToWrite) /* Lagging behind? */
1786 LogFlowFunc(("Warning: Only written %RU32 / %RU32 bytes, expect lags\n", cbWrittenToStream, cbToWrite));
1787 }
1788
1789 /* Always report all data as being written;
1790 * backends who were not able to catch up have to deal with it themselves. */
1791 Assert(cbElapsed >= cbToWrite);
1792 cbElapsed -= cbToWrite;
1793 }
1794}
1795
1796#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
1797static void ichac97TimerMaybeStart(PAC97STATE pThis)
1798{
1799 if (pThis->cStreamsActive == 0) /* Only start the timer if there at least is one active streams. */
1800 return;
1801
1802 if (!pThis->pTimer)
1803 return;
1804
1805 if (ASMAtomicReadBool(&pThis->fTimerActive) == true) /* Already started? */
1806 return;
1807
1808 LogRel2(("AC97: Starting transfers\n"));
1809
1810 /* Set timer flag. */
1811 ASMAtomicXchgBool(&pThis->fTimerActive, true);
1812
1813 /* Update current time timestamp. */
1814 pThis->uTimerTS = TMTimerGet(pThis->pTimer);
1815
1816 /* Start transfers. */
1817 ichac97DoTransfers(pThis);
1818}
1819
1820static void ichac97TimerMaybeStop(PAC97STATE pThis)
1821{
1822 if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
1823 return;
1824
1825 if (!pThis->pTimer)
1826 return;
1827
1828 if (ASMAtomicReadBool(&pThis->fTimerActive) == false) /* Already stopped? */
1829 return;
1830
1831 LogRel2(("AC97: Stopping transfers\n"));
1832
1833 /* Set timer flag. */
1834 ASMAtomicXchgBool(&pThis->fTimerActive, false);
1835}
1836
1837static void ichac97DoTransfers(PAC97STATE pThis)
1838{
1839 AssertPtrReturnVoid(pThis);
1840
1841 STAM_PROFILE_START(&pThis->StatTimer, a);
1842
1843 uint64_t cTicksNow = TMTimerGet(pThis->pTimer);
1844
1845 /* Update current time timestamp. */
1846 pThis->uTimerTS = cTicksNow;
1847
1848 /* Flag indicating whether to kick the timer again for the next DMA transfer or sink processing. */
1849 bool fKickTimer = false;
1850
1851 ichac97StreamUpdate(pThis, &pThis->StreamLineIn);
1852 ichac97StreamUpdate(pThis, &pThis->StreamMicIn);
1853 ichac97StreamUpdate(pThis, &pThis->StreamOut);
1854
1855 /* Do we need to kick the timer again? */
1856 if ( AudioMixerSinkIsActive(ichac97IndexToSink(pThis, pThis->StreamLineIn.u8Strm))
1857 || AudioMixerSinkIsActive(ichac97IndexToSink(pThis, pThis->StreamMicIn.u8Strm))
1858 || AudioMixerSinkIsActive(ichac97IndexToSink(pThis, pThis->StreamOut.u8Strm)))
1859 {
1860 fKickTimer = true;
1861 }
1862
1863 if ( ASMAtomicReadBool(&pThis->fTimerActive)
1864 || fKickTimer)
1865 {
1866 /* Kick the timer again. */
1867 uint64_t cTicks = pThis->cTimerTicks;
1868 /** @todo adjust cTicks down by now much cbOutMin represents. */
1869 TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
1870 }
1871 else
1872 LogRel2(("AC97: Stopped transfers\n"));
1873
1874 STAM_PROFILE_STOP(&pThis->StatTimer, a);
1875}
1876#endif /* !VBOX_WITH_AUDIO_AC97_CALLBACKS */
1877
1878static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1879{
1880 RT_NOREF(pDevIns, pTimer);
1881
1882 PAC97STATE pThis = (PAC97STATE)pvUser;
1883 Assert(pThis == PDMINS_2_DATA(pDevIns, PAC97STATE));
1884 AssertPtr(pThis);
1885
1886 ichac97DoTransfers(pThis);
1887}
1888
1889/**
1890 * Does a single DMA transfer for a specific AC'97 stream.
1891 * This either can be a read or write operation, depending on the AC'97 stream.
1892 *
1893 * @returns IPRT status code.
1894 * @param pThis AC'97 state.
1895 * @param pStream AC'97 stream to do the DMA transfer for.
1896 * @param pvBuf Pointer to buffer data to write data to / read data from.
1897 * @param cbBuf Size of buffer (in bytes).
1898 * @param cbToProcess Size (in bytes) to transfer (read/write).
1899 * @param pcbProcessed Size (in bytes) transferred (read/written). Optional.
1900 */
1901static int ichac97DoDMA(PAC97STATE pThis, PAC97STREAM pStream, void *pvBuf, uint32_t cbBuf,
1902 uint32_t cbToProcess, uint32_t *pcbProcessed)
1903{
1904 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1905 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
1906 /* pcbProcessed is optional. */
1907
1908 PAC97BMREGS pRegs = &pStream->Regs;
1909
1910 if (pRegs->sr & AC97_SR_DCH) /* Controller halted? */
1911 {
1912 if (pRegs->cr & AC97_CR_RPBM) /* Bus master operation starts. */
1913 {
1914 switch (pStream->u8Strm)
1915 {
1916 case AC97SOUNDSOURCE_PO_INDEX:
1917 ichac97WriteBUP(pThis, cbToProcess);
1918 break;
1919
1920 default:
1921 break;
1922 }
1923 }
1924
1925 if (pcbProcessed)
1926 *pcbProcessed = 0;
1927
1928 return VINF_SUCCESS;
1929 }
1930
1931 /* BCIS flag still set? Skip iteration. */
1932 if (pRegs->sr & AC97_SR_BCIS)
1933 {
1934 Log3Func(("[SD%RU8] BCIS set\n", pStream->u8Strm));
1935
1936 if (pcbProcessed)
1937 *pcbProcessed = 0;
1938
1939 return VINF_SUCCESS;
1940 }
1941
1942 uint32_t cbLeft = RT_MIN((uint32_t)(pRegs->picb << 1), RT_MIN(cbToProcess, cbBuf));
1943 uint32_t cbTotal = 0;
1944 uint32_t cbChunk;
1945
1946 int rc = VINF_SUCCESS;
1947
1948 Log3Func(("[SD%RU8] cbToProcess=%RU32, cbLeft=%RU32\n", pStream->u8Strm, cbToProcess, cbLeft));
1949
1950 while (cbLeft)
1951 {
1952 if (!pRegs->bd_valid)
1953 {
1954 Log3Func(("Invalid buffer descriptor, fetching next one ...\n"));
1955 ichac97StreamFetchBDLE(pThis, pStream);
1956 }
1957
1958 if (!pRegs->picb) /* Got a new buffer descriptor, that is, the position is 0? */
1959 {
1960 Log3Func(("Fresh buffer descriptor %RU8 is empty, addr=%#x, len=%#x, skipping\n",
1961 pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len));
1962 if (pRegs->civ == pRegs->lvi)
1963 {
1964 pRegs->sr |= AC97_SR_DCH; /** @todo r=andy Also set CELV? */
1965 pThis->bup_flag = 0;
1966
1967 rc = VINF_EOF;
1968 break;
1969 }
1970
1971 pRegs->sr &= ~AC97_SR_CELV;
1972 pRegs->civ = pRegs->piv;
1973 pRegs->piv = (pRegs->piv + 1) % 32; /** @todo r=andy Define for max BDLEs? */
1974
1975 ichac97StreamFetchBDLE(pThis, pStream);
1976 continue;
1977 }
1978
1979 cbChunk = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */
1980 Assert(cbChunk);
1981
1982 switch (pStream->u8Strm)
1983 {
1984 case AC97SOUNDSOURCE_PO_INDEX: /* Output */
1985 {
1986 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pRegs->bd.addr,
1987 (uint8_t *)pvBuf + cbTotal, cbChunk);
1988 break;
1989 }
1990
1991 case AC97SOUNDSOURCE_PI_INDEX: /* Input */
1992 case AC97SOUNDSOURCE_MC_INDEX: /* Input */
1993 {
1994 PDMDevHlpPhysWrite(pThis->CTX_SUFF(pDevIns), pRegs->bd.addr,
1995 (uint8_t *)pvBuf + cbTotal, cbChunk);
1996 break;
1997 }
1998
1999 default:
2000 AssertMsgFailed(("Stream #%RU8 not supported\n", pStream->u8Strm));
2001 rc = VERR_NOT_SUPPORTED;
2002 break;
2003 }
2004
2005 if (RT_FAILURE(rc))
2006 break;
2007
2008#ifdef AC97_DEBUG_DUMP_PCM_DATA
2009 RTFILE fh;
2010 RTFileOpen(&fh,
2011 pStream->u8Strm == AC97SOUNDSOURCE_PO_INDEX
2012 ? AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97DMARead.pcm" : AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97DMAWrite.pcm",
2013 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
2014 RTFileWrite(fh, (uint8_t *)pvBuf + cbTotal, cbChunk, NULL);
2015 RTFileClose(fh);
2016#endif
2017
2018 if (cbChunk)
2019 {
2020 cbTotal += cbChunk;
2021 Assert(cbLeft >= cbChunk);
2022 cbLeft -= cbChunk;
2023 Assert((cbChunk & 1) == 0); /* Else the following shift won't work */
2024
2025 pRegs->picb -= (cbChunk >> 1); /** @todo r=andy Assumes 16bit samples. */
2026 pRegs->bd.addr += cbChunk;
2027 }
2028
2029 LogFlowFunc(("[SD%RU8]: cbChunk=%RU32, cbLeft=%RU32, cbTotal=%RU32, rc=%Rrc\n",
2030 pStream->u8Strm, cbChunk, cbLeft, cbTotal, rc));
2031
2032 if (!pRegs->picb)
2033 {
2034 uint32_t new_sr = pRegs->sr & ~AC97_SR_CELV;
2035
2036 if (pRegs->bd.ctl_len & AC97_BD_IOC)
2037 {
2038 new_sr |= AC97_SR_BCIS;
2039 }
2040
2041 if (pRegs->civ == pRegs->lvi)
2042 {
2043 /* Did we run out of data? */
2044 LogFunc(("Underrun CIV (%RU8) == LVI (%RU8)\n", pRegs->civ, pRegs->lvi));
2045
2046 new_sr |= AC97_SR_LVBCI | AC97_SR_DCH | AC97_SR_CELV;
2047 pThis->bup_flag = (pRegs->bd.ctl_len & AC97_BD_BUP) ? BUP_LAST : 0;
2048
2049 rc = VINF_EOF;
2050 }
2051 else
2052 {
2053 pRegs->civ = pRegs->piv;
2054 pRegs->piv = (pRegs->piv + 1) % 32; /** @todo r=andy Define for max BDLEs? */
2055 ichac97StreamFetchBDLE(pThis, pStream);
2056 }
2057
2058 ichac97StreamUpdateSR(pThis, pStream, new_sr);
2059 }
2060
2061 if (/* All data processed? */
2062 rc == VINF_EOF
2063 /* ... or an error occurred? */
2064 || RT_FAILURE(rc))
2065 {
2066 break;
2067 }
2068 }
2069
2070 if (RT_SUCCESS(rc))
2071 {
2072 if (pcbProcessed)
2073 *pcbProcessed = cbTotal;
2074 }
2075
2076 LogFlowFuncLeaveRC(rc);
2077 return rc;
2078}
2079
2080/**
2081 * @callback_method_impl{FNIOMIOPORTIN}
2082 */
2083static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32Val, unsigned cbVal)
2084{
2085 RT_NOREF(pDevIns);
2086 PAC97STATE pThis = (PAC97STATE)pvUser;
2087
2088 /* Get the index of the NABMBAR port. */
2089 const uint32_t uPortIdx = Port - pThis->IOPortBase[1];
2090
2091 PAC97STREAM pStream = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
2092 PAC97BMREGS pRegs = NULL;
2093
2094 if (pStream)
2095 {
2096 pRegs = &pStream->Regs;
2097
2098 int rc2 = RTCritSectEnter(&pStream->CritSect);
2099 AssertRC(rc2);
2100 }
2101
2102 int rc = VINF_SUCCESS;
2103
2104 switch (cbVal)
2105 {
2106 case 1:
2107 {
2108 switch (uPortIdx)
2109 {
2110 case AC97_CAS:
2111 /* Codec Access Semaphore Register */
2112 Log3Func(("CAS %d\n", pThis->cas));
2113 *pu32Val = pThis->cas;
2114 pThis->cas = 1;
2115 break;
2116 case PI_CIV:
2117 case PO_CIV:
2118 case MC_CIV:
2119 /* Current Index Value Register */
2120 *pu32Val = pRegs->civ;
2121 Log3Func(("CIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
2122 break;
2123 case PI_LVI:
2124 case PO_LVI:
2125 case MC_LVI:
2126 /* Last Valid Index Register */
2127 *pu32Val = pRegs->lvi;
2128 Log3Func(("LVI[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
2129 break;
2130 case PI_PIV:
2131 case PO_PIV:
2132 case MC_PIV:
2133 /* Prefetched Index Value Register */
2134 *pu32Val = pRegs->piv;
2135 Log3Func(("PIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
2136 break;
2137 case PI_CR:
2138 case PO_CR:
2139 case MC_CR:
2140 /* Control Register */
2141 *pu32Val = pRegs->cr;
2142 Log3Func(("CR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
2143 break;
2144 case PI_SR:
2145 case PO_SR:
2146 case MC_SR:
2147 /* Status Register (lower part) */
2148 *pu32Val = RT_LO_U8(pRegs->sr);
2149 Log3Func(("SRb[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
2150 break;
2151 default:
2152 *pu32Val = UINT32_MAX;
2153 LogFunc(("U nabm readb %#x -> %#x\n", Port, *pu32Val));
2154 break;
2155 }
2156 break;
2157 }
2158
2159 case 2:
2160 {
2161 switch (uPortIdx)
2162 {
2163 case PI_SR:
2164 case PO_SR:
2165 case MC_SR:
2166 /* Status Register */
2167 *pu32Val = pRegs->sr;
2168 Log3Func(("SR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
2169 break;
2170 case PI_PICB:
2171 case PO_PICB:
2172 case MC_PICB:
2173 /* Position in Current Buffer */
2174 *pu32Val = pRegs->picb;
2175 Log3Func(("PICB[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
2176 break;
2177 default:
2178 *pu32Val = UINT32_MAX;
2179 LogFunc(("U nabm readw %#x -> %#x\n", Port, *pu32Val));
2180 break;
2181 }
2182 break;
2183 }
2184
2185 case 4:
2186 {
2187 switch (uPortIdx)
2188 {
2189 case PI_BDBAR:
2190 case PO_BDBAR:
2191 case MC_BDBAR:
2192 /* Buffer Descriptor Base Address Register */
2193 *pu32Val = pRegs->bdbar;
2194 Log3Func(("BMADDR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
2195 break;
2196 case PI_CIV:
2197 case PO_CIV:
2198 case MC_CIV:
2199 /* 32-bit access: Current Index Value Register +
2200 * Last Valid Index Register +
2201 * Status Register */
2202 *pu32Val = pRegs->civ | (pRegs->lvi << 8) | (pRegs->sr << 16); /** @todo r=andy Use RT_MAKE_U32_FROM_U8. */
2203 Log3Func(("CIV LVI SR[%d] -> %#x, %#x, %#x\n",
2204 AC97_PORT2IDX(uPortIdx), pRegs->civ, pRegs->lvi, pRegs->sr));
2205 break;
2206 case PI_PICB:
2207 case PO_PICB:
2208 case MC_PICB:
2209 /* 32-bit access: Position in Current Buffer Register +
2210 * Prefetched Index Value Register +
2211 * Control Register */
2212 *pu32Val = pRegs->picb | (pRegs->piv << 16) | (pRegs->cr << 24); /** @todo r=andy Use RT_MAKE_U32_FROM_U8. */
2213 Log3Func(("PICB PIV CR[%d] -> %#x %#x %#x %#x\n",
2214 AC97_PORT2IDX(uPortIdx), *pu32Val, pRegs->picb, pRegs->piv, pRegs->cr));
2215 break;
2216 case AC97_GLOB_CNT:
2217 /* Global Control */
2218 *pu32Val = pThis->glob_cnt;
2219 Log3Func(("glob_cnt -> %#x\n", *pu32Val));
2220 break;
2221 case AC97_GLOB_STA:
2222 /* Global Status */
2223 *pu32Val = pThis->glob_sta | AC97_GS_S0CR;
2224 Log3Func(("glob_sta -> %#x\n", *pu32Val));
2225 break;
2226 default:
2227 *pu32Val = UINT32_MAX;
2228 LogFunc(("U nabm readl %#x -> %#x\n", Port, *pu32Val));
2229 break;
2230 }
2231 break;
2232 }
2233
2234 default:
2235 {
2236 AssertFailed();
2237 rc = VERR_IOM_IOPORT_UNUSED;
2238 }
2239 }
2240
2241 if (pStream)
2242 {
2243 int rc2 = RTCritSectLeave(&pStream->CritSect);
2244 AssertRC(rc2);
2245 }
2246
2247 return rc;
2248}
2249
2250/**
2251 * @callback_method_impl{FNIOMIOPORTOUT}
2252 */
2253static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
2254 uint32_t u32Val, unsigned cbVal)
2255{
2256 RT_NOREF(pDevIns);
2257 PAC97STATE pThis = (PAC97STATE)pvUser;
2258
2259 /* Get the index of the NABMBAR register. */
2260 const uint32_t uPortIdx = Port - pThis->IOPortBase[1];
2261
2262 PAC97STREAM pStream = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
2263 PAC97BMREGS pRegs = NULL;
2264
2265 if (pStream)
2266 {
2267 pRegs = &pStream->Regs;
2268
2269 int rc2 = RTCritSectEnter(&pStream->CritSect);
2270 AssertRC(rc2);
2271 }
2272
2273 switch (cbVal)
2274 {
2275 case 1:
2276 {
2277 switch (uPortIdx)
2278 {
2279 /*
2280 * Last Valid Index.
2281 */
2282 case PI_LVI:
2283 case PO_LVI:
2284 case MC_LVI:
2285 {
2286 if ( (pRegs->cr & AC97_CR_RPBM)
2287 && (pRegs->sr & AC97_SR_DCH))
2288 {
2289 pRegs->sr &= ~(AC97_SR_DCH | AC97_SR_CELV);
2290 pRegs->civ = pRegs->piv;
2291 pRegs->piv = (pRegs->piv + 1) % 32;
2292
2293 ichac97StreamFetchBDLE(pThis, pStream);
2294 }
2295 pRegs->lvi = u32Val % 32;
2296 Log3Func(("[SD%RU8] LVI <- %#x\n", pStream->u8Strm, u32Val));
2297 break;
2298 }
2299
2300 /*
2301 * Control Registers.
2302 */
2303 case PI_CR:
2304 case PO_CR:
2305 case MC_CR:
2306 {
2307 Log3Func(("[SD%RU8] CR <- %#x (cr %#x)\n", pStream->u8Strm, u32Val, pRegs->cr));
2308
2309 if (u32Val & AC97_CR_RR) /* Busmaster reset. */
2310 {
2311 Log3Func(("[SD%RU8] Reset\n", pStream->u8Strm));
2312
2313 /* Make sure that Run/Pause Bus Master bit (RPBM) is cleared (0). */
2314 Assert((pRegs->cr & AC97_CR_RPBM) == 0);
2315
2316 ichac97StreamResetBMRegs(pThis, pStream);
2317 }
2318 else
2319 {
2320 pRegs->cr = u32Val & AC97_CR_VALID_MASK;
2321
2322 if (!(pRegs->cr & AC97_CR_RPBM))
2323 {
2324 Log3Func(("[SD%RU8] Disable\n", pStream->u8Strm));
2325
2326 ichac97StreamEnable(pThis, pStream, false /* fEnable */);
2327
2328 pRegs->sr |= AC97_SR_DCH;
2329 }
2330 else
2331 {
2332 Log3Func(("[SD%RU8] Enable\n", pStream->u8Strm));
2333
2334 pRegs->civ = pRegs->piv;
2335 pRegs->piv = (pRegs->piv + 1) % 32;
2336
2337 pRegs->sr &= ~AC97_SR_DCH;
2338
2339 /* Fetch the initial BDLE descriptor. */
2340 ichac97StreamFetchBDLE(pThis, pStream);
2341
2342 ichac97StreamEnable(pThis, pStream, true /* fEnable */);
2343 }
2344 }
2345 break;
2346 }
2347
2348 /*
2349 * Status Registers.
2350 */
2351 case PI_SR:
2352 case PO_SR:
2353 case MC_SR:
2354 {
2355 pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK);
2356 ichac97StreamUpdateSR(pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK));
2357 Log3Func(("[SD%RU8] SR <- %#x (sr %#x)\n", pStream->u8Strm, u32Val, pRegs->sr));
2358 break;
2359 }
2360
2361 default:
2362 LogFunc(("Unimplemented: %#x <- %#x (Byte)\n", Port, u32Val));
2363 break;
2364 }
2365 break;
2366 }
2367
2368 case 2:
2369 {
2370 switch (uPortIdx)
2371 {
2372 case PI_SR:
2373 case PO_SR:
2374 case MC_SR:
2375 /* Status Register */
2376 pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK);
2377 ichac97StreamUpdateSR(pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK));
2378 Log3Func(("[SD%RU8] SR <- %#x (sr %#x)\n", pStream->u8Strm, u32Val, pRegs->sr));
2379 break;
2380 default:
2381 LogFunc(("Unimplemented: %#x <- %#x (Word)\n", Port, u32Val));
2382 break;
2383 }
2384 break;
2385 }
2386
2387 case 4:
2388 {
2389 switch (uPortIdx)
2390 {
2391 case PI_BDBAR:
2392 case PO_BDBAR:
2393 case MC_BDBAR:
2394 /* Buffer Descriptor list Base Address Register */
2395 pRegs->bdbar = u32Val & ~3;
2396 Log3Func(("[SD%RU8] BDBAR <- %#x (bdbar %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->bdbar));
2397 break;
2398 case AC97_GLOB_CNT:
2399 /* Global Control */
2400 if (u32Val & AC97_GC_WR)
2401 ichac97WarmReset(pThis);
2402 if (u32Val & AC97_GC_CR)
2403 ichac97ColdReset(pThis);
2404 if (!(u32Val & (AC97_GC_WR | AC97_GC_CR)))
2405 pThis->glob_cnt = u32Val & AC97_GC_VALID_MASK;
2406 Log3Func(("glob_cnt <- %#x (glob_cnt %#x)\n", u32Val, pThis->glob_cnt));
2407 break;
2408 case AC97_GLOB_STA:
2409 /* Global Status */
2410 pThis->glob_sta &= ~(u32Val & AC97_GS_WCLEAR_MASK);
2411 pThis->glob_sta |= (u32Val & ~(AC97_GS_WCLEAR_MASK | AC97_GS_RO_MASK)) & AC97_GS_VALID_MASK;
2412 Log3Func(("glob_sta <- %#x (glob_sta %#x)\n", u32Val, pThis->glob_sta));
2413 break;
2414 default:
2415 LogFunc(("Unimplemented: %#x <- %#x (DWord)\n", Port, u32Val));
2416 break;
2417 }
2418 break;
2419 }
2420
2421 default:
2422 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cbVal, u32Val));
2423 break;
2424 }
2425
2426 if (pStream)
2427 {
2428 int rc2 = RTCritSectLeave(&pStream->CritSect);
2429 AssertRC(rc2);
2430 }
2431
2432 return VINF_SUCCESS;
2433}
2434
2435/**
2436 * @callback_method_impl{FNIOMIOPORTIN}
2437 */
2438static DECLCALLBACK(int) ichac97IOPortNAMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32Val, unsigned cbVal)
2439{
2440 RT_NOREF(pDevIns);
2441 PAC97STATE pThis = (PAC97STATE)pvUser;
2442
2443 int rc = VINF_SUCCESS;
2444
2445 switch (cbVal)
2446 {
2447 case 1:
2448 {
2449 Log3Func(("U nam readb %#x\n", Port));
2450 pThis->cas = 0;
2451 *pu32Val = UINT32_MAX;
2452 break;
2453 }
2454
2455 case 2:
2456 {
2457 uint32_t index = Port - pThis->IOPortBase[0];
2458 *pu32Val = UINT32_MAX;
2459 pThis->cas = 0;
2460 switch (index)
2461 {
2462 default:
2463 *pu32Val = ichac97MixerGet(pThis, index);
2464 Log3Func(("nam readw %#x -> %#x\n", Port, *pu32Val));
2465 break;
2466 }
2467 break;
2468 }
2469
2470 case 4:
2471 {
2472 Log3Func(("U nam readl %#x\n", Port));
2473 pThis->cas = 0;
2474 *pu32Val = UINT32_MAX;
2475 break;
2476 }
2477
2478 default:
2479 {
2480 AssertFailed();
2481 rc = VERR_IOM_IOPORT_UNUSED;
2482 }
2483 }
2484
2485 return rc;
2486}
2487
2488/**
2489 * @callback_method_impl{FNIOMIOPORTOUT}
2490 */
2491static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32Val, unsigned cbVal)
2492{
2493 RT_NOREF(pDevIns);
2494 PAC97STATE pThis = (PAC97STATE)pvUser;
2495
2496 switch (cbVal)
2497 {
2498 case 1:
2499 {
2500 Log3Func(("U nam writeb %#x <- %#x\n", Port, u32Val));
2501 pThis->cas = 0;
2502 break;
2503 }
2504
2505 case 2:
2506 {
2507 uint32_t index = Port - pThis->IOPortBase[0];
2508 pThis->cas = 0;
2509 switch (index)
2510 {
2511 case AC97_Reset:
2512 ichac97Reset(pThis->CTX_SUFF(pDevIns));
2513 break;
2514 case AC97_Powerdown_Ctrl_Stat:
2515 u32Val &= ~0xf;
2516 u32Val |= ichac97MixerGet(pThis, index) & 0xf;
2517 ichac97MixerSet(pThis, index, u32Val);
2518 break;
2519 case AC97_Master_Volume_Mute:
2520 if (pThis->uCodecModel == AC97_CODEC_AD1980)
2521 {
2522 if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_LOSEL)
2523 break; /* Register controls surround (rear), do nothing. */
2524 }
2525 ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME_MASTER, u32Val);
2526 break;
2527 case AC97_Headphone_Volume_Mute:
2528 if (pThis->uCodecModel == AC97_CODEC_AD1980)
2529 {
2530 if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_HPSEL)
2531 {
2532 /* Register controls PCM (front) outputs. */
2533 ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME_MASTER, u32Val);
2534 }
2535 }
2536 break;
2537 case AC97_PCM_Out_Volume_Mute:
2538 ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_FRONT, u32Val);
2539 break;
2540 case AC97_Line_In_Volume_Mute:
2541 ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_LINE_IN, u32Val);
2542 break;
2543 case AC97_Record_Select:
2544 ichac97RecordSelect(pThis, u32Val);
2545 break;
2546 case AC97_Vendor_ID1:
2547 case AC97_Vendor_ID2:
2548 LogFunc(("Attempt to write vendor ID to %#x\n", u32Val));
2549 break;
2550 case AC97_Extended_Audio_ID:
2551 LogFunc(("Attempt to write extended audio ID to %#x\n", u32Val));
2552 break;
2553 case AC97_Extended_Audio_Ctrl_Stat:
2554 if (!(u32Val & AC97_EACS_VRA))
2555 {
2556 ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate, 48000);
2557 ichac97StreamReOpen(pThis, &pThis->StreamOut);
2558
2559 ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate, 48000);
2560 ichac97StreamReOpen(pThis, &pThis->StreamLineIn);
2561 }
2562 else
2563 LogRel2(("AC97: Variable rate audio (VRA) is not supported\n"));
2564
2565 if (!(u32Val & AC97_EACS_VRM))
2566 {
2567 ichac97MixerSet(pThis, AC97_MIC_ADC_Rate, 48000);
2568 ichac97StreamReOpen(pThis, &pThis->StreamMicIn);
2569 }
2570 else
2571 LogRel2(("AC97: Variable rate microphone audio (VRM) is not supported\n"));
2572
2573 LogFunc(("Setting extended audio control to %#x\n", u32Val));
2574 ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, u32Val);
2575 break;
2576 case AC97_PCM_Front_DAC_Rate:
2577 if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRA)
2578 {
2579 ichac97MixerSet(pThis, index, u32Val);
2580 LogFunc(("Set front DAC rate to %RU32\n", u32Val));
2581 ichac97StreamReOpen(pThis, &pThis->StreamOut);
2582 }
2583 else
2584 AssertMsgFailed(("Attempt to set front DAC rate to %RU32, but VRA is not set\n", u32Val));
2585 break;
2586 case AC97_MIC_ADC_Rate:
2587 if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRM)
2588 {
2589 ichac97MixerSet(pThis, index, u32Val);
2590 LogFunc(("Set MIC ADC rate to %RU32\n", u32Val));
2591 ichac97StreamReOpen(pThis, &pThis->StreamMicIn);
2592 }
2593 else
2594 AssertMsgFailed(("Attempt to set MIC ADC rate to %RU32, but VRM is not set\n", u32Val));
2595 break;
2596 case AC97_PCM_LR_ADC_Rate:
2597 if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRA)
2598 {
2599 ichac97MixerSet(pThis, index, u32Val);
2600 LogFunc(("Set front LR ADC rate to %RU32\n", u32Val));
2601 ichac97StreamReOpen(pThis, &pThis->StreamLineIn);
2602 }
2603 else
2604 AssertMsgFailed(("Attempt to set LR ADC rate to %RU32, but VRA is not set\n", u32Val));
2605 break;
2606 default:
2607 LogFunc(("U nam writew %#x <- %#x\n", Port, u32Val));
2608 ichac97MixerSet(pThis, index, u32Val);
2609 break;
2610 }
2611 break;
2612 }
2613
2614 case 4:
2615 {
2616 Log3Func(("U nam writel %#x <- %#x\n", Port, u32Val));
2617 pThis->cas = 0;
2618 break;
2619 }
2620
2621 default:
2622 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cbVal, u32Val));
2623 break;
2624 }
2625
2626 return VINF_SUCCESS;
2627}
2628
2629
2630/**
2631 * @callback_method_impl{FNPCIIOREGIONMAP}
2632 */
2633static DECLCALLBACK(int) ichac97IOPortMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
2634 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
2635{
2636 RT_NOREF(cb, enmType);
2637 PAC97STATE pThis = RT_FROM_MEMBER(pPciDev, AC97STATE, PciDev);
2638 RTIOPORT Port = (RTIOPORT)GCPhysAddress;
2639
2640 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2641 Assert(cb >= 0x20);
2642
2643 if (iRegion > 1) /* We support 2 regions max. at the moment. */
2644 return VERR_INVALID_PARAMETER;
2645
2646 int rc;
2647 if (iRegion == 0)
2648 rc = PDMDevHlpIOPortRegister(pDevIns, Port, 256, pThis,
2649 ichac97IOPortNAMWrite, ichac97IOPortNAMRead,
2650 NULL, NULL, "ICHAC97 NAM");
2651 else
2652 rc = PDMDevHlpIOPortRegister(pDevIns, Port, 64, pThis,
2653 ichac97IOPortNABMWrite, ichac97IOPortNABMRead,
2654 NULL, NULL, "ICHAC97 NABM");
2655 if (RT_FAILURE(rc))
2656 return rc;
2657
2658 pThis->IOPortBase[iRegion] = Port;
2659 return VINF_SUCCESS;
2660}
2661
2662DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID)
2663{
2664 switch (uID)
2665 {
2666 case AC97SOUNDSOURCE_PI_INDEX: return &pThis->StreamLineIn;
2667 case AC97SOUNDSOURCE_MC_INDEX: return &pThis->StreamMicIn;
2668 case AC97SOUNDSOURCE_PO_INDEX: return &pThis->StreamOut;
2669 default: break;
2670 }
2671
2672 return NULL;
2673}
2674
2675#ifdef IN_RING3
2676static int ichac97SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStream)
2677{
2678 RT_NOREF(pDevIns);
2679 PAC97BMREGS pRegs = &pStream->Regs;
2680
2681 SSMR3PutU32(pSSM, pRegs->bdbar);
2682 SSMR3PutU8( pSSM, pRegs->civ);
2683 SSMR3PutU8( pSSM, pRegs->lvi);
2684 SSMR3PutU16(pSSM, pRegs->sr);
2685 SSMR3PutU16(pSSM, pRegs->picb);
2686 SSMR3PutU8( pSSM, pRegs->piv);
2687 SSMR3PutU8( pSSM, pRegs->cr);
2688 SSMR3PutS32(pSSM, pRegs->bd_valid);
2689 SSMR3PutU32(pSSM, pRegs->bd.addr);
2690 SSMR3PutU32(pSSM, pRegs->bd.ctl_len);
2691
2692 return VINF_SUCCESS;
2693}
2694
2695/**
2696 * @callback_method_impl{FNSSMDEVSAVEEXEC}
2697 */
2698static DECLCALLBACK(int) ichac97SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2699{
2700 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2701
2702 LogFlowFuncEnter();
2703
2704 SSMR3PutU32(pSSM, pThis->glob_cnt);
2705 SSMR3PutU32(pSSM, pThis->glob_sta);
2706 SSMR3PutU32(pSSM, pThis->cas);
2707
2708 /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
2709 /* Note: The order the streams are saved here is critical, so don't touch. */
2710 int rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StreamLineIn);
2711 AssertRC(rc2);
2712 rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StreamOut);
2713 AssertRC(rc2);
2714 rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StreamMicIn);
2715 AssertRC(rc2);
2716
2717 SSMR3PutMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
2718
2719 uint8_t active[AC97SOUNDSOURCE_LAST_INDEX];
2720
2721 active[AC97SOUNDSOURCE_PI_INDEX] = ichac97StreamIsEnabled(pThis, &pThis->StreamLineIn) ? 1 : 0;
2722 active[AC97SOUNDSOURCE_PO_INDEX] = ichac97StreamIsEnabled(pThis, &pThis->StreamOut) ? 1 : 0;
2723 active[AC97SOUNDSOURCE_MC_INDEX] = ichac97StreamIsEnabled(pThis, &pThis->StreamMicIn) ? 1 : 0;
2724
2725 SSMR3PutMem(pSSM, active, sizeof(active));
2726
2727 LogFlowFuncLeaveRC(VINF_SUCCESS);
2728 return VINF_SUCCESS;
2729}
2730
2731static int ichac97LoadStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStream)
2732{
2733 RT_NOREF(pDevIns);
2734 PAC97BMREGS pRegs = &pStream->Regs;
2735
2736 SSMR3GetU32(pSSM, &pRegs->bdbar);
2737 SSMR3GetU8( pSSM, &pRegs->civ);
2738 SSMR3GetU8( pSSM, &pRegs->lvi);
2739 SSMR3GetU16(pSSM, &pRegs->sr);
2740 SSMR3GetU16(pSSM, &pRegs->picb);
2741 SSMR3GetU8( pSSM, &pRegs->piv);
2742 SSMR3GetU8( pSSM, &pRegs->cr);
2743 SSMR3GetS32(pSSM, &pRegs->bd_valid);
2744 SSMR3GetU32(pSSM, &pRegs->bd.addr);
2745 SSMR3GetU32(pSSM, &pRegs->bd.ctl_len);
2746
2747 return VINF_SUCCESS;
2748}
2749
2750/**
2751 * @callback_method_impl{FNSSMDEVLOADEXEC}
2752 */
2753static DECLCALLBACK(int) ichac97LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2754{
2755 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2756
2757 LogRel2(("ichac97LoadExec: uVersion=%RU32, uPass=0x%x\n", uVersion, uPass));
2758
2759 AssertMsgReturn (uVersion == AC97_SSM_VERSION, ("%RU32\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
2760 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
2761
2762 SSMR3GetU32(pSSM, &pThis->glob_cnt);
2763 SSMR3GetU32(pSSM, &pThis->glob_sta);
2764 SSMR3GetU32(pSSM, &pThis->cas);
2765
2766 /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
2767 /* Note: The order the streams are loaded here is critical, so don't touch. */
2768 int rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StreamLineIn);
2769 AssertRC(rc2);
2770 rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StreamOut);
2771 AssertRC(rc2);
2772 rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StreamMicIn);
2773 AssertRC(rc2);
2774
2775 SSMR3GetMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
2776
2777 /** @todo r=andy Stream IDs are hardcoded to certain streams. */
2778 uint8_t uaStrmsActive[AC97SOUNDSOURCE_LAST_INDEX];
2779 SSMR3GetMem(pSSM, uaStrmsActive, sizeof(uaStrmsActive));
2780
2781 ichac97RecordSelect(pThis, ichac97MixerGet(pThis, AC97_Record_Select));
2782# define V_(a, b) ichac97MixerSetVolume(pThis, a, b, ichac97MixerGet(pThis, a))
2783 V_(AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER);
2784 V_(AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT);
2785 V_(AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN);
2786 V_(AC97_Mic_Volume_Mute, PDMAUDIOMIXERCTL_MIC_IN);
2787# undef V_
2788 if (pThis->uCodecModel == AC97_CODEC_AD1980)
2789 if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_HPSEL)
2790 ichac97MixerSetVolume(pThis, AC97_Headphone_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER,
2791 ichac97MixerGet(pThis, AC97_Headphone_Volume_Mute));
2792
2793 rc2 = ichac97StreamsCreate(pThis);
2794 if (RT_SUCCESS(rc2))
2795 {
2796 /** @todo r=andy Stream IDs are hardcoded to certain streams. */
2797 rc2 = ichac97StreamEnable(pThis, &pThis->StreamLineIn, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_PI_INDEX]));
2798 if (RT_SUCCESS(rc2))
2799 rc2 = ichac97StreamEnable(pThis, &pThis->StreamMicIn, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_MC_INDEX]));
2800 if (RT_SUCCESS(rc2))
2801 rc2 = ichac97StreamEnable(pThis, &pThis->StreamOut, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_PO_INDEX]));
2802 }
2803
2804 pThis->bup_flag = 0;
2805 pThis->last_samp = 0;
2806
2807 return VINF_SUCCESS;
2808}
2809
2810
2811/**
2812 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2813 */
2814static DECLCALLBACK(void *) ichac97QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
2815{
2816 PAC97STATE pThis = RT_FROM_MEMBER(pInterface, AC97STATE, IBase);
2817 Assert(&pThis->IBase == pInterface);
2818
2819 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2820 return NULL;
2821}
2822
2823
2824/**
2825 * Powers off the device.
2826 *
2827 * @param pDevIns Device instance to power off.
2828 */
2829static DECLCALLBACK(void) ichac97PowerOff(PPDMDEVINS pDevIns)
2830{
2831 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2832
2833 LogRel2(("AC97: Powering off ...\n"));
2834
2835 /* Note: Involves mixer stream / sink destruction, so also do this here
2836 * instead of in ichac97Destruct(). */
2837 ichac97StreamsDestroy(pThis);
2838
2839 /**
2840 * Note: Destroy the mixer while powering off and *not* in ichac97Destruct,
2841 * giving the mixer the chance to release any references held to
2842 * PDM audio streams it maintains.
2843 */
2844 if (pThis->pMixer)
2845 {
2846 AudioMixerDestroy(pThis->pMixer);
2847 pThis->pMixer = NULL;
2848 }
2849}
2850
2851
2852/**
2853 * @interface_method_impl{PDMDEVREG,pfnReset}
2854 *
2855 * @remarks The original sources didn't install a reset handler, but it seems to
2856 * make sense to me so we'll do it.
2857 */
2858static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns)
2859{
2860 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2861
2862 LogFlowFuncEnter();
2863
2864 /*
2865 * Reset the device state (will need pDrv later).
2866 */
2867 ichac97StreamResetBMRegs(pThis, &pThis->StreamLineIn);
2868 ichac97StreamResetBMRegs(pThis, &pThis->StreamMicIn);
2869 ichac97StreamResetBMRegs(pThis, &pThis->StreamOut);
2870
2871 /*
2872 * Reset the mixer too. The Windows XP driver seems to rely on
2873 * this. At least it wants to read the vendor id before it resets
2874 * the codec manually.
2875 */
2876 ichac97MixerReset(pThis);
2877
2878 /*
2879 * Reset all streams.
2880 */
2881 ichac97StreamReset(pThis, &pThis->StreamLineIn);
2882 ichac97StreamReset(pThis, &pThis->StreamMicIn);
2883 ichac97StreamReset(pThis, &pThis->StreamOut);
2884
2885 LogRel(("AC97: Reset\n"));
2886}
2887
2888
2889/**
2890 * @interface_method_impl{PDMDEVREG,pfnDestruct}
2891 */
2892static DECLCALLBACK(int) ichac97Destruct(PPDMDEVINS pDevIns)
2893{
2894 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2895
2896 LogFlowFuncEnter();
2897
2898 PAC97DRIVER pDrv, pDrvNext;
2899 RTListForEachSafe(&pThis->lstDrv, pDrv, pDrvNext, AC97DRIVER, Node)
2900 {
2901 RTListNodeRemove(&pDrv->Node);
2902 RTMemFree(pDrv);
2903 }
2904
2905 /* Sanity. */
2906 Assert(RTListIsEmpty(&pThis->lstDrv));
2907
2908 int rc;
2909#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
2910 rc = RTCritSectDelete(&pThis->csTimer);
2911#else
2912 rc = VINF_SUCCESS;
2913#endif
2914
2915 LogFlowFuncLeaveRC(rc);
2916 return rc;
2917}
2918
2919
2920/**
2921 * Attach command, internal version.
2922 *
2923 * This is called to let the device attach to a driver for a specified LUN
2924 * during runtime. This is not called during VM construction, the device
2925 * constructor has to attach to all the available drivers.
2926 *
2927 * @returns VBox status code.
2928 * @param pDevIns The device instance.
2929 * @param pDrv Driver to (re-)use for (re-)attaching to.
2930 * If NULL is specified, a new driver will be created and appended
2931 * to the driver list.
2932 * @param uLUN The logical unit which is being detached.
2933 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2934 */
2935static DECLCALLBACK(int) ichac97AttachInternal(PPDMDEVINS pDevIns, PAC97DRIVER pDrv, unsigned uLUN, uint32_t fFlags)
2936{
2937 RT_NOREF(fFlags);
2938 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2939
2940 /*
2941 * Attach driver.
2942 */
2943 char *pszDesc = NULL;
2944 if (RTStrAPrintf(&pszDesc, "Audio driver port (AC'97) for LUN #%u", uLUN) <= 0)
2945 AssertReleaseMsgReturn(pszDesc,
2946 ("Not enough memory for AC'97 driver port description of LUN #%u\n", uLUN),
2947 VERR_NO_MEMORY);
2948
2949 PPDMIBASE pDrvBase;
2950 int rc = PDMDevHlpDriverAttach(pDevIns, uLUN,
2951 &pThis->IBase, &pDrvBase, pszDesc);
2952 if (RT_SUCCESS(rc))
2953 {
2954 if (pDrv == NULL)
2955 pDrv = (PAC97DRIVER)RTMemAllocZ(sizeof(AC97DRIVER));
2956 if (pDrv)
2957 {
2958 pDrv->pDrvBase = pDrvBase;
2959 pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
2960 AssertMsg(pDrv->pConnector != NULL, ("Configuration error: LUN #%u has no host audio interface, rc=%Rrc\n", uLUN, rc));
2961 pDrv->pAC97State = pThis;
2962 pDrv->uLUN = uLUN;
2963
2964 /*
2965 * For now we always set the driver at LUN 0 as our primary
2966 * host backend. This might change in the future.
2967 */
2968 if (pDrv->uLUN == 0)
2969 pDrv->Flags |= PDMAUDIODRVFLAGS_PRIMARY;
2970
2971 LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
2972
2973 /* Attach to driver list if not attached yet. */
2974 if (!pDrv->fAttached)
2975 {
2976 RTListAppend(&pThis->lstDrv, &pDrv->Node);
2977 pDrv->fAttached = true;
2978 }
2979 }
2980 else
2981 rc = VERR_NO_MEMORY;
2982 }
2983 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2984 LogFunc(("No attached driver for LUN #%u\n", uLUN));
2985
2986 if (RT_FAILURE(rc))
2987 {
2988 /* Only free this string on failure;
2989 * must remain valid for the live of the driver instance. */
2990 RTStrFree(pszDesc);
2991 }
2992
2993 LogFunc(("iLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
2994 return rc;
2995}
2996
2997
2998/**
2999 * Attach command.
3000 *
3001 * This is called to let the device attach to a driver for a specified LUN
3002 * during runtime. This is not called during VM construction, the device
3003 * constructor has to attach to all the available drivers.
3004 *
3005 * @returns VBox status code.
3006 * @param pDevIns The device instance.
3007 * @param uLUN The logical unit which is being detached.
3008 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
3009 */
3010static DECLCALLBACK(int) ichac97Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
3011{
3012 return ichac97AttachInternal(pDevIns, NULL /* pDrv */, uLUN, fFlags);
3013}
3014
3015static DECLCALLBACK(void) ichac97Detach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
3016{
3017 RT_NOREF(pDevIns, uLUN, fFlags);
3018 LogFunc(("iLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
3019}
3020
3021/**
3022 * Re-attach.
3023 *
3024 * @returns VBox status code.
3025 * @param pThis Device instance.
3026 * @param pDrv Driver instance used for attaching to.
3027 * If NULL is specified, a new driver will be created and appended
3028 * to the driver list.
3029 * @param uLUN The logical unit which is being re-detached.
3030 * @param pszDriver Driver name.
3031 */
3032static int ichac97Reattach(PAC97STATE pThis, PAC97DRIVER pDrv, uint8_t uLUN, const char *pszDriver)
3033{
3034 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
3035 AssertPtrReturn(pszDriver, VERR_INVALID_POINTER);
3036
3037 PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
3038 PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
3039 PCFGMNODE pDev0 = CFGMR3GetChild(pRoot, "Devices/ichac97/0/");
3040
3041 /* Remove LUN branch. */
3042 CFGMR3RemoveNode(CFGMR3GetChildF(pDev0, "LUN#%u/", uLUN));
3043
3044 if (pDrv)
3045 {
3046 /* Re-use a driver instance => detach the driver before. */
3047 int rc = PDMDevHlpDriverDetach(pThis->pDevInsR3, PDMIBASE_2_PDMDRV(pDrv->pDrvBase), 0 /* fFlags */);
3048 if (RT_FAILURE(rc))
3049 return rc;
3050 }
3051
3052#define RC_CHECK() if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; }
3053
3054 int rc;
3055 do
3056 {
3057 PCFGMNODE pLunL0;
3058 rc = CFGMR3InsertNodeF(pDev0, &pLunL0, "LUN#%u/", uLUN); RC_CHECK();
3059 rc = CFGMR3InsertString(pLunL0, "Driver", "AUDIO"); RC_CHECK();
3060 rc = CFGMR3InsertNode(pLunL0, "Config/", NULL); RC_CHECK();
3061
3062 PCFGMNODE pLunL1, pLunL2;
3063 rc = CFGMR3InsertNode (pLunL0, "AttachedDriver/", &pLunL1); RC_CHECK();
3064 rc = CFGMR3InsertNode (pLunL1, "Config/", &pLunL2); RC_CHECK();
3065 rc = CFGMR3InsertString(pLunL1, "Driver", pszDriver); RC_CHECK();
3066
3067 rc = CFGMR3InsertString(pLunL2, "AudioDriver", pszDriver); RC_CHECK();
3068
3069 } while (0);
3070
3071 if (RT_SUCCESS(rc))
3072 rc = ichac97AttachInternal(pThis->pDevInsR3, pDrv, uLUN, 0 /* fFlags */);
3073
3074 LogFunc(("pThis=%p, uLUN=%u, pszDriver=%s, rc=%Rrc\n", pThis, uLUN, pszDriver, rc));
3075
3076#undef RC_CHECK
3077
3078 return rc;
3079}
3080
3081/**
3082 * @interface_method_impl{PDMDEVREG,pfnConstruct}
3083 */
3084static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
3085{
3086 RT_NOREF(iInstance);
3087 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
3088
3089 /* NB: This must be done *before* any possible failure (and running the destructor). */
3090 RTListInit(&pThis->lstDrv);
3091
3092 Assert(iInstance == 0);
3093 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3094
3095 /*
3096 * Validations.
3097 */
3098 if (!CFGMR3AreValuesValid(pCfg,
3099 "Codec\0"
3100 "TimerHz\0"))
3101 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
3102 N_("Invalid configuration for the AC'97 device"));
3103
3104 /*
3105 * Read config data.
3106 */
3107 char szCodec[20];
3108 int rc = CFGMR3QueryStringDef(pCfg, "Codec", &szCodec[0], sizeof(szCodec), "STAC9700");
3109 if (RT_FAILURE(rc))
3110 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
3111 N_("AC'97 configuration error: Querying \"Codec\" as string failed"));
3112
3113#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
3114 uint16_t uTimerHz;
3115 rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, AC97_TIMER_HZ /* Default value, if not set. */);
3116 if (RT_FAILURE(rc))
3117 return PDMDEV_SET_ERROR(pDevIns, rc,
3118 N_("AC'97 configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
3119#endif
3120
3121 /*
3122 * The AD1980 codec (with corresponding PCI subsystem vendor ID) is whitelisted
3123 * in the Linux kernel; Linux makes no attempt to measure the data rate and assumes
3124 * 48 kHz rate, which is exactly what we need. Same goes for AD1981B.
3125 */
3126 if (!strcmp(szCodec, "STAC9700"))
3127 pThis->uCodecModel = AC97_CODEC_STAC9700;
3128 else if (!strcmp(szCodec, "AD1980"))
3129 pThis->uCodecModel = AC97_CODEC_AD1980;
3130 else if (!strcmp(szCodec, "AD1981B"))
3131 pThis->uCodecModel = AC97_CODEC_AD1981B;
3132 else
3133 {
3134 return PDMDevHlpVMSetError(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, RT_SRC_POS,
3135 N_("AC'97 configuration error: The \"Codec\" value \"%s\" is unsupported"),
3136 szCodec);
3137 }
3138
3139 /*
3140 * Initialize data (most of it anyway).
3141 */
3142 pThis->pDevInsR3 = pDevIns;
3143 /* IBase */
3144 pThis->IBase.pfnQueryInterface = ichac97QueryInterface;
3145
3146 /* PCI Device (the assertions will be removed later) */
3147 PCIDevSetVendorId (&pThis->PciDev, 0x8086); /* 00 ro - intel. */ Assert(pThis->PciDev.abConfig[0x00] == 0x86); Assert(pThis->PciDev.abConfig[0x01] == 0x80);
3148 PCIDevSetDeviceId (&pThis->PciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */ Assert(pThis->PciDev.abConfig[0x02] == 0x15); Assert(pThis->PciDev.abConfig[0x03] == 0x24);
3149 PCIDevSetCommand (&pThis->PciDev, 0x0000); /* 04 rw,ro - pcicmd. */ Assert(pThis->PciDev.abConfig[0x04] == 0x00); Assert(pThis->PciDev.abConfig[0x05] == 0x00);
3150 PCIDevSetStatus (&pThis->PciDev, VBOX_PCI_STATUS_DEVSEL_MEDIUM | VBOX_PCI_STATUS_FAST_BACK); /* 06 rwc?,ro? - pcists. */ Assert(pThis->PciDev.abConfig[0x06] == 0x80); Assert(pThis->PciDev.abConfig[0x07] == 0x02);
3151 PCIDevSetRevisionId (&pThis->PciDev, 0x01); /* 08 ro - rid. */ Assert(pThis->PciDev.abConfig[0x08] == 0x01);
3152 PCIDevSetClassProg (&pThis->PciDev, 0x00); /* 09 ro - pi. */ Assert(pThis->PciDev.abConfig[0x09] == 0x00);
3153 PCIDevSetClassSub (&pThis->PciDev, 0x01); /* 0a ro - scc; 01 == Audio. */ Assert(pThis->PciDev.abConfig[0x0a] == 0x01);
3154 PCIDevSetClassBase (&pThis->PciDev, 0x04); /* 0b ro - bcc; 04 == multimedia. */ Assert(pThis->PciDev.abConfig[0x0b] == 0x04);
3155 PCIDevSetHeaderType (&pThis->PciDev, 0x00); /* 0e ro - headtyp. */ Assert(pThis->PciDev.abConfig[0x0e] == 0x00);
3156 PCIDevSetBaseAddress (&pThis->PciDev, 0, /* 10 rw - nambar - native audio mixer base. */
3157 true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.abConfig[0x10] == 0x01); Assert(pThis->PciDev.abConfig[0x11] == 0x00); Assert(pThis->PciDev.abConfig[0x12] == 0x00); Assert(pThis->PciDev.abConfig[0x13] == 0x00);
3158 PCIDevSetBaseAddress (&pThis->PciDev, 1, /* 14 rw - nabmbar - native audio bus mastering. */
3159 true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.abConfig[0x14] == 0x01); Assert(pThis->PciDev.abConfig[0x15] == 0x00); Assert(pThis->PciDev.abConfig[0x16] == 0x00); Assert(pThis->PciDev.abConfig[0x17] == 0x00);
3160 PCIDevSetInterruptLine (&pThis->PciDev, 0x00); /* 3c rw. */ Assert(pThis->PciDev.abConfig[0x3c] == 0x00);
3161 PCIDevSetInterruptPin (&pThis->PciDev, 0x01); /* 3d ro - INTA#. */ Assert(pThis->PciDev.abConfig[0x3d] == 0x01);
3162
3163 if (pThis->uCodecModel == AC97_CODEC_AD1980)
3164 {
3165 PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x1028); /* 2c ro - Dell.) */
3166 PCIDevSetSubSystemId (&pThis->PciDev, 0x0177); /* 2e ro. */
3167 }
3168 else if (pThis->uCodecModel == AC97_CODEC_AD1981B)
3169 {
3170 PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x1028); /* 2c ro - Dell.) */
3171 PCIDevSetSubSystemId (&pThis->PciDev, 0x01ad); /* 2e ro. */
3172 }
3173 else
3174 {
3175 PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x8086); /* 2c ro - Intel.) */
3176 PCIDevSetSubSystemId (&pThis->PciDev, 0x0000); /* 2e ro. */
3177 }
3178
3179 /*
3180 * Register the PCI device, it's I/O regions, the timer and the
3181 * saved state item.
3182 */
3183 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
3184 if (RT_FAILURE(rc))
3185 return rc;
3186
3187 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 256, PCI_ADDRESS_SPACE_IO, ichac97IOPortMap);
3188 if (RT_FAILURE(rc))
3189 return rc;
3190
3191 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 64, PCI_ADDRESS_SPACE_IO, ichac97IOPortMap);
3192 if (RT_FAILURE(rc))
3193 return rc;
3194
3195 rc = PDMDevHlpSSMRegister(pDevIns, AC97_SSM_VERSION, sizeof(*pThis), ichac97SaveExec, ichac97LoadExec);
3196 if (RT_FAILURE(rc))
3197 return rc;
3198
3199 /*
3200 * Attach driver.
3201 */
3202 uint8_t uLUN;
3203 for (uLUN = 0; uLUN < UINT8_MAX; ++uLUN)
3204 {
3205 LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
3206 rc = ichac97AttachInternal(pDevIns, NULL /* pDrv */, uLUN, 0 /* fFlags */);
3207 if (RT_FAILURE(rc))
3208 {
3209 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
3210 rc = VINF_SUCCESS;
3211 else if (rc == VERR_AUDIO_BACKEND_INIT_FAILED)
3212 {
3213 ichac97Reattach(pThis, NULL /* pDrv */, uLUN, "NullAudio");
3214 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
3215 N_("Host audio backend initialization has failed. Selecting the NULL audio backend "
3216 "with the consequence that no sound is audible"));
3217 /* Attaching to the NULL audio backend will never fail. */
3218 rc = VINF_SUCCESS;
3219 }
3220 break;
3221 }
3222 }
3223
3224 LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
3225
3226 if (RT_SUCCESS(rc))
3227 rc = AudioMixerCreate("AC'97 Mixer", 0 /* uFlags */, &pThis->pMixer);
3228
3229 ichac97Reset(pDevIns);
3230
3231 if (RT_SUCCESS(rc))
3232 {
3233 ichac97StreamsCreate(pThis);
3234
3235#ifdef VBOX_WITH_AUDIO_AC97_ONETIME_INIT
3236 PAC97DRIVER pDrv;
3237 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
3238 {
3239 /*
3240 * Only primary drivers are critical for the VM to run. Everything else
3241 * might not worth showing an own error message box in the GUI.
3242 */
3243 if (!(pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY))
3244 continue;
3245
3246 PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
3247 AssertPtr(pCon);
3248
3249 bool fValidLineIn = AudioMixerStreamIsValid(pDrv->LineIn.pMixStrm);
3250 bool fValidMicIn = AudioMixerStreamIsValid(pDrv->MicIn.pMixStrm);
3251 bool fValidOut = AudioMixerStreamIsValid(pDrv->Out.pMixStrm);
3252
3253 if ( !fValidLineIn
3254 && !fValidMicIn
3255 && !fValidOut)
3256 {
3257 LogRel(("AC97: Falling back to NULL backend (no sound audible)\n"));
3258
3259 /* Destroy the streams before re-attaching the NULL driver. */
3260 ichac97StreamsDestroy(pThis);
3261
3262 ichac97Reset(pDevIns);
3263 ichac97Reattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
3264
3265 /* Re-create the streams after re-attaching. */
3266 ichac97StreamsCreate(pThis);
3267
3268 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
3269 N_("No audio devices could be opened. Selecting the NULL audio backend "
3270 "with the consequence that no sound is audible"));
3271 }
3272 else
3273 {
3274 bool fWarn = false;
3275
3276 PDMAUDIOBACKENDCFG backendCfg;
3277 int rc2 = pCon->pfnGetConfig(pCon, &backendCfg);
3278 if (RT_SUCCESS(rc2))
3279 {
3280 if (backendCfg.cMaxStreamsIn)
3281 {
3282 /* If the audio backend supports two or more input streams at once,
3283 * warn if one of our two inputs (microphone-in and line-in) failed to initialize. */
3284 if (backendCfg.cMaxStreamsIn >= 2)
3285 fWarn = !fValidLineIn || !fValidMicIn;
3286 /* If the audio backend only supports one input stream at once (e.g. pure ALSA, and
3287 * *not* ALSA via PulseAudio plugin!), only warn if both of our inputs failed to initialize.
3288 * One of the two simply is not in use then. */
3289 else if (backendCfg.cMaxStreamsIn == 1)
3290 fWarn = !fValidLineIn && !fValidMicIn;
3291 /* Don't warn if our backend is not able of supporting any input streams at all. */
3292 }
3293
3294 if ( !fWarn
3295 && backendCfg.cMaxStreamsOut)
3296 {
3297 fWarn = !fValidOut;
3298 }
3299 }
3300 else
3301 {
3302 LogRel(("AC97: Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n", pDrv->uLUN, rc2));
3303 fWarn = true;
3304 }
3305
3306 if (fWarn)
3307 {
3308 char szMissingStreams[255] = "";
3309 size_t len = 0;
3310 if (!fValidLineIn)
3311 {
3312 LogRel(("AC97: WARNING: Unable to open PCM line input for LUN #%RU8!\n", pDrv->uLUN));
3313 len = RTStrPrintf(szMissingStreams, sizeof(szMissingStreams), "PCM Input");
3314 }
3315 if (!fValidMicIn)
3316 {
3317 LogRel(("AC97: WARNING: Unable to open PCM microphone input for LUN #%RU8!\n", pDrv->uLUN));
3318 len += RTStrPrintf(szMissingStreams + len,
3319 sizeof(szMissingStreams) - len, len ? ", PCM Microphone" : "PCM Microphone");
3320 }
3321 if (!fValidOut)
3322 {
3323 LogRel(("AC97: WARNING: Unable to open PCM output for LUN #%RU8!\n", pDrv->uLUN));
3324 len += RTStrPrintf(szMissingStreams + len,
3325 sizeof(szMissingStreams) - len, len ? ", PCM Output" : "PCM Output");
3326 }
3327
3328 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
3329 N_("Some AC'97 audio streams (%s) could not be opened. Guest applications generating audio "
3330 "output or depending on audio input may hang. Make sure your host audio device "
3331 "is working properly. Check the logfile for error messages of the audio "
3332 "subsystem"), szMissingStreams);
3333 }
3334 }
3335 }
3336#endif /* VBOX_WITH_AUDIO_AC97_ONETIME_INIT */
3337 }
3338
3339#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
3340 if (RT_SUCCESS(rc))
3341 {
3342 rc = RTCritSectInit(&pThis->csTimer);
3343 if (RT_SUCCESS(rc))
3344 {
3345 /* Create the emulation timer. */
3346 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ichac97Timer, pThis,
3347 TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchAc97", &pThis->pTimer);
3348 AssertRCReturn(rc, rc);
3349
3350 if (RT_SUCCESS(rc))
3351 {
3352 pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimer) / uTimerHz;
3353 pThis->uTimerTS = TMTimerGet(pThis->pTimer);
3354 LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
3355 }
3356 }
3357 }
3358#else /* !VBOX_WITH_AUDIO_AC97_CALLBACKS */
3359 if (RT_SUCCESS(rc))
3360 {
3361 PAC97DRIVER pDrv;
3362 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
3363 {
3364 /* Only register primary driver.
3365 * The device emulation does the output multiplexing then. */
3366 if (!(pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY))
3367 continue;
3368
3369 PDMAUDIOCALLBACK AudioCallbacks[2];
3370
3371 AC97CALLBACKCTX Ctx = { pThis, pDrv };
3372
3373 AudioCallbacks[0].enmType = PDMAUDIOCALLBACKTYPE_INPUT;
3374 AudioCallbacks[0].pfnCallback = ac97CallbackInput;
3375 AudioCallbacks[0].pvCtx = &Ctx;
3376 AudioCallbacks[0].cbCtx = sizeof(AC97CALLBACKCTX);
3377
3378 AudioCallbacks[1].enmType = PDMAUDIOCALLBACKTYPE_OUTPUT;
3379 AudioCallbacks[1].pfnCallback = ac97CallbackOutput;
3380 AudioCallbacks[1].pvCtx = &Ctx;
3381 AudioCallbacks[1].cbCtx = sizeof(AC97CALLBACKCTX);
3382
3383 rc = pDrv->pConnector->pfnRegisterCallbacks(pDrv->pConnector, AudioCallbacks, RT_ELEMENTS(AudioCallbacks));
3384 if (RT_FAILURE(rc))
3385 break;
3386 }
3387 }
3388#endif /* VBOX_WITH_AUDIO_AC97_CALLBACKS */
3389
3390#ifdef VBOX_WITH_STATISTICS
3391 if (RT_SUCCESS(rc))
3392 {
3393 /*
3394 * Register statistics.
3395 */
3396 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer, STAMTYPE_PROFILE, "/Devices/AC97/Timer", STAMUNIT_TICKS_PER_CALL, "Profiling ichac97Timer.");
3397 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn, STAMTYPE_PROFILE, "/Devices/AC97/Input", STAMUNIT_TICKS_PER_CALL, "Profiling input.");
3398 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatOut, STAMTYPE_PROFILE, "/Devices/AC97/Output", STAMUNIT_TICKS_PER_CALL, "Profiling output.");
3399 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, "/Devices/AC97/BytesRead" , STAMUNIT_BYTES, "Bytes read from AC97 emulation.");
3400 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "/Devices/AC97/BytesWritten", STAMUNIT_BYTES, "Bytes written to AC97 emulation.");
3401 }
3402#endif
3403
3404#ifdef AC97_DEBUG_DUMP_PCM_DATA
3405 RTFileDelete(AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97DMARead.pcm");
3406 RTFileDelete(AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97DMAWrite.pcm");
3407 RTFileDelete(AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97StreamRead.pcm");
3408 RTFileDelete(AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97StreamWrite.pcm");
3409#endif
3410
3411 LogFlowFuncLeaveRC(rc);
3412 return rc;
3413}
3414
3415/**
3416 * The device registration structure.
3417 */
3418const PDMDEVREG g_DeviceICHAC97 =
3419{
3420 /* u32Version */
3421 PDM_DEVREG_VERSION,
3422 /* szName */
3423 "ichac97",
3424 /* szRCMod */
3425 "",
3426 /* szR0Mod */
3427 "",
3428 /* pszDescription */
3429 "ICH AC'97 Audio Controller",
3430 /* fFlags */
3431 PDM_DEVREG_FLAGS_DEFAULT_BITS,
3432 /* fClass */
3433 PDM_DEVREG_CLASS_AUDIO,
3434 /* cMaxInstances */
3435 1,
3436 /* cbInstance */
3437 sizeof(AC97STATE),
3438 /* pfnConstruct */
3439 ichac97Construct,
3440 /* pfnDestruct */
3441 ichac97Destruct,
3442 /* pfnRelocate */
3443 NULL,
3444 /* pfnMemSetup */
3445 NULL,
3446 /* pfnPowerOn */
3447 NULL,
3448 /* pfnReset */
3449 ichac97Reset,
3450 /* pfnSuspend */
3451 NULL,
3452 /* pfnResume */
3453 NULL,
3454 /* pfnAttach */
3455 ichac97Attach,
3456 /* pfnDetach */
3457 ichac97Detach,
3458 /* pfnQueryInterface. */
3459 NULL,
3460 /* pfnInitComplete */
3461 NULL,
3462 /* pfnPowerOff */
3463 ichac97PowerOff,
3464 /* pfnSoftReset */
3465 NULL,
3466 /* u32VersionEnd */
3467 PDM_DEVREG_VERSION
3468};
3469
3470#endif /* !IN_RING3 */
3471#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
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