VirtualBox

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

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

Audio: Implemented support for audio device enumeration handling, audio device information and audio backend notifications. This will enable to let the backends tell the audio subsystem that the host audio configuration has changed and react accordingly to it. For now only the Core Audio backend supports device enumeration. Further this also will get rid of the static initialization on the device emulation side, which, if at VM startup no audio input(s) / output(s) were available, was triggering a warning. The NULL backend therefore does not need to act as a (static) fallback anymore.

Work in progress.

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