VirtualBox

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

Last change on this file since 62370 was 62355, checked in by vboxsync, 9 years ago

Audio/DevIchAc97.cpp: Bail out of the DMA transfer loop if an error occurred.

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

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