VirtualBox

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

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

scm: cleaning up todos

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