VirtualBox

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

Last change on this file since 63846 was 63819, checked in by vboxsync, 9 years ago

Audio/DevIchAc97.cpp: More status register (SR) fun.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette