VirtualBox

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

Last change on this file since 62337 was 62280, checked in by vboxsync, 9 years ago

AC97: Headphone volume control behaves like master volume control (no gain).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 102.6 KB
Line 
1/* $Id: DevIchAc97.cpp 62280 2016-07-15 14:24:58Z 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 (rc == VINF_EOF) /* All data processed? */
1605 break;
1606 }
1607
1608 if (RT_SUCCESS(rc))
1609 {
1610 if (pcbProcessed)
1611 *pcbProcessed = cbTotal;
1612 }
1613
1614 LogFlowFuncLeaveRC(rc);
1615 return rc;
1616}
1617
1618/**
1619 * @callback_method_impl{FNIOMIOPORTIN}
1620 */
1621static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
1622 uint32_t *pu32Val, unsigned cbVal)
1623{
1624 PAC97STATE pThis = (PAC97STATE)pvUser;
1625
1626 /* Get the index of the NABMBAR port. */
1627 const uint32_t uPortIdx = Port - pThis->IOPortBase[1];
1628
1629 PAC97STREAM pStream = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
1630 PAC97BMREGS pRegs = pStream ? &pStream->Regs : NULL;
1631
1632 switch (cbVal)
1633 {
1634 case 1:
1635 {
1636 switch (uPortIdx)
1637 {
1638 case AC97_CAS:
1639 /* Codec Access Semaphore Register */
1640 LogFlowFunc(("CAS %d\n", pThis->cas));
1641 *pu32Val = pThis->cas;
1642 pThis->cas = 1;
1643 break;
1644 case PI_CIV:
1645 case PO_CIV:
1646 case MC_CIV:
1647 /* Current Index Value Register */
1648 *pu32Val = pRegs->civ;
1649 LogFlowFunc(("CIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
1650 break;
1651 case PI_LVI:
1652 case PO_LVI:
1653 case MC_LVI:
1654 /* Last Valid Index Register */
1655 *pu32Val = pRegs->lvi;
1656 LogFlowFunc(("LVI[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
1657 break;
1658 case PI_PIV:
1659 case PO_PIV:
1660 case MC_PIV:
1661 /* Prefetched Index Value Register */
1662 *pu32Val = pRegs->piv;
1663 LogFlowFunc(("PIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
1664 break;
1665 case PI_CR:
1666 case PO_CR:
1667 case MC_CR:
1668 /* Control Register */
1669 *pu32Val = pRegs->cr;
1670 LogFlowFunc(("CR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
1671 break;
1672 case PI_SR:
1673 case PO_SR:
1674 case MC_SR:
1675 /* Status Register (lower part) */
1676 *pu32Val = pRegs->sr & 0xff; /** @todo r=andy Use RT_LO_U8. */
1677 LogFlowFunc(("SRb[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
1678 break;
1679 default:
1680 *pu32Val = UINT32_MAX;
1681 LogFlowFunc(("U nabm readb %#x -> %#x\n", Port, *pu32Val));
1682 break;
1683 }
1684 break;
1685 }
1686
1687 case 2:
1688 {
1689 switch (uPortIdx)
1690 {
1691 case PI_SR:
1692 case PO_SR:
1693 case MC_SR:
1694 /* Status Register */
1695 *pu32Val = pRegs->sr;
1696 LogFlowFunc(("SR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
1697 break;
1698 case PI_PICB:
1699 case PO_PICB:
1700 case MC_PICB:
1701 /* Position in Current Buffer */
1702 *pu32Val = pRegs->picb;
1703 LogFlowFunc(("PICB[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
1704 break;
1705 default:
1706 *pu32Val = UINT32_MAX;
1707 LogFlowFunc(("U nabm readw %#x -> %#x\n", Port, *pu32Val));
1708 break;
1709 }
1710 break;
1711 }
1712
1713 case 4:
1714 {
1715 switch (uPortIdx)
1716 {
1717 case PI_BDBAR:
1718 case PO_BDBAR:
1719 case MC_BDBAR:
1720 /* Buffer Descriptor Base Address Register */
1721 *pu32Val = pRegs->bdbar;
1722 LogFlowFunc(("BMADDR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
1723 break;
1724 case PI_CIV:
1725 case PO_CIV:
1726 case MC_CIV:
1727 /* 32-bit access: Current Index Value Register +
1728 * Last Valid Index Register +
1729 * Status Register */
1730 *pu32Val = pRegs->civ | (pRegs->lvi << 8) | (pRegs->sr << 16); /** @todo r=andy Use RT_MAKE_U32_FROM_U8. */
1731 LogFlowFunc(("CIV LVI SR[%d] -> %#x, %#x, %#x\n",
1732 AC97_PORT2IDX(uPortIdx), pRegs->civ, pRegs->lvi, pRegs->sr));
1733 break;
1734 case PI_PICB:
1735 case PO_PICB:
1736 case MC_PICB:
1737 /* 32-bit access: Position in Current Buffer Register +
1738 * Prefetched Index Value Register +
1739 * Control Register */
1740 *pu32Val = pRegs->picb | (pRegs->piv << 16) | (pRegs->cr << 24); /** @todo r=andy Use RT_MAKE_U32_FROM_U8. */
1741 LogFlowFunc(("PICB PIV CR[%d] -> %#x %#x %#x %#x\n",
1742 AC97_PORT2IDX(uPortIdx), *pu32Val, pRegs->picb, pRegs->piv, pRegs->cr));
1743 break;
1744 case AC97_GLOB_CNT:
1745 /* Global Control */
1746 *pu32Val = pThis->glob_cnt;
1747 LogFlowFunc(("glob_cnt -> %#x\n", *pu32Val));
1748 break;
1749 case AC97_GLOB_STA:
1750 /* Global Status */
1751 *pu32Val = pThis->glob_sta | AC97_GS_S0CR;
1752 LogFlowFunc(("glob_sta -> %#x\n", *pu32Val));
1753 break;
1754 default:
1755 *pu32Val = UINT32_MAX;
1756 LogFlowFunc(("U nabm readl %#x -> %#x\n", Port, *pu32Val));
1757 break;
1758 }
1759 break;
1760 }
1761
1762 default:
1763 return VERR_IOM_IOPORT_UNUSED;
1764 }
1765 return VINF_SUCCESS;
1766}
1767
1768/**
1769 * @callback_method_impl{FNIOMIOPORTOUT}
1770 */
1771static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
1772 uint32_t u32Val, unsigned cbVal)
1773{
1774 PAC97STATE pThis = (PAC97STATE)pvUser;
1775
1776 /* Get the index of the NABMBAR register. */
1777 const uint32_t uPortIdx = Port - pThis->IOPortBase[1];
1778
1779 PAC97STREAM pStream = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
1780 PAC97BMREGS pRegs = pStream ? &pStream->Regs : NULL;
1781
1782 switch (cbVal)
1783 {
1784 case 1:
1785 {
1786 switch (uPortIdx)
1787 {
1788 case PI_LVI:
1789 case PO_LVI:
1790 case MC_LVI:
1791 /* Last Valid Index */
1792 if ((pRegs->cr & AC97_CR_RPBM) && (pRegs->sr & AC97_SR_DCH))
1793 {
1794 pRegs->sr &= ~(AC97_SR_DCH | AC97_SR_CELV);
1795 pRegs->civ = pRegs->piv;
1796 pRegs->piv = (pRegs->piv + 1) % 32;
1797
1798 ichac97StreamFetchBDLE(pThis, pStream);
1799 }
1800 pRegs->lvi = u32Val % 32;
1801 LogFlowFunc(("LVI[%d] <- %#x\n", AC97_PORT2IDX(uPortIdx), u32Val));
1802 break;
1803 case PI_CR:
1804 case PO_CR:
1805 case MC_CR:
1806 {
1807 /* Control Register */
1808 if (u32Val & AC97_CR_RR) /* Busmaster reset */
1809 {
1810 ichac97StreamResetBMRegs(pThis, pStream);
1811 }
1812 else
1813 {
1814 pRegs->cr = u32Val & AC97_CR_VALID_MASK;
1815 if (!(pRegs->cr & AC97_CR_RPBM))
1816 {
1817 ichac97StreamSetActive(pThis, pStream, false /* fActive */);
1818 pRegs->sr |= AC97_SR_DCH;
1819 }
1820 else
1821 {
1822 pRegs->civ = pRegs->piv;
1823 pRegs->piv = (pRegs->piv + 1) % 32;
1824
1825 ichac97StreamFetchBDLE(pThis, pStream);
1826
1827 pRegs->sr &= ~AC97_SR_DCH;
1828 ichac97StreamSetActive(pThis, pStream, true /* fActive */);
1829 }
1830 }
1831 LogFlowFunc(("CR[%d] <- %#x (cr %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->cr));
1832 break;
1833 }
1834 case PI_SR:
1835 case PO_SR:
1836 case MC_SR:
1837 /* Status Register */
1838 pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK);
1839 ichac97StreamUpdateStatus(pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK));
1840 LogFlowFunc(("SR[%d] <- %#x (sr %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->sr));
1841 break;
1842 default:
1843 LogFlowFunc(("U nabm writeb %#x <- %#x\n", Port, u32Val));
1844 break;
1845 }
1846 break;
1847 }
1848
1849 case 2:
1850 {
1851 switch (uPortIdx)
1852 {
1853 case PI_SR:
1854 case PO_SR:
1855 case MC_SR:
1856 /* Status Register */
1857 pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK);
1858 ichac97StreamUpdateStatus(pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK));
1859 LogFlowFunc(("SR[%d] <- %#x (sr %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->sr));
1860 break;
1861 default:
1862 LogFlowFunc(("U nabm writew %#x <- %#x\n", Port, u32Val));
1863 break;
1864 }
1865 break;
1866 }
1867
1868 case 4:
1869 {
1870 switch (uPortIdx)
1871 {
1872 case PI_BDBAR:
1873 case PO_BDBAR:
1874 case MC_BDBAR:
1875 /* Buffer Descriptor list Base Address Register */
1876 pRegs->bdbar = u32Val & ~3;
1877 LogFlowFunc(("BDBAR[%d] <- %#x (bdbar %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->bdbar));
1878 break;
1879 case AC97_GLOB_CNT:
1880 /* Global Control */
1881 if (u32Val & AC97_GC_WR)
1882 ichac97WarmReset(pThis);
1883 if (u32Val & AC97_GC_CR)
1884 ichac97ColdReset(pThis);
1885 if (!(u32Val & (AC97_GC_WR | AC97_GC_CR)))
1886 pThis->glob_cnt = u32Val & AC97_GC_VALID_MASK;
1887 LogFlowFunc(("glob_cnt <- %#x (glob_cnt %#x)\n", u32Val, pThis->glob_cnt));
1888 break;
1889 case AC97_GLOB_STA:
1890 /* Global Status */
1891 pThis->glob_sta &= ~(u32Val & AC97_GS_WCLEAR_MASK);
1892 pThis->glob_sta |= (u32Val & ~(AC97_GS_WCLEAR_MASK | AC97_GS_RO_MASK)) & AC97_GS_VALID_MASK;
1893 LogFlowFunc(("glob_sta <- %#x (glob_sta %#x)\n", u32Val, pThis->glob_sta));
1894 break;
1895 default:
1896 LogFlowFunc(("U nabm writel %#x <- %#x\n", Port, u32Val));
1897 break;
1898 }
1899 break;
1900 }
1901
1902 default:
1903 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cbVal, u32Val));
1904 break;
1905 }
1906 return VINF_SUCCESS;
1907}
1908
1909/**
1910 * @callback_method_impl{FNIOMIOPORTIN}
1911 */
1912static DECLCALLBACK(int) ichac97IOPortNAMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32Val, unsigned cbVal)
1913{
1914 PAC97STATE pThis = (PAC97STATE)pvUser;
1915
1916 switch (cbVal)
1917 {
1918 case 1:
1919 {
1920 LogFlowFunc(("U nam readb %#x\n", Port));
1921 pThis->cas = 0;
1922 *pu32Val = UINT32_MAX;
1923 break;
1924 }
1925
1926 case 2:
1927 {
1928 uint32_t index = Port - pThis->IOPortBase[0];
1929 *pu32Val = UINT32_MAX;
1930 pThis->cas = 0;
1931 switch (index)
1932 {
1933 default:
1934 *pu32Val = ichac97MixerGet(pThis, index);
1935 LogFlowFunc(("nam readw %#x -> %#x\n", Port, *pu32Val));
1936 break;
1937 }
1938 break;
1939 }
1940
1941 case 4:
1942 {
1943 LogFlowFunc(("U nam readl %#x\n", Port));
1944 pThis->cas = 0;
1945 *pu32Val = UINT32_MAX;
1946 break;
1947 }
1948
1949 default:
1950 return VERR_IOM_IOPORT_UNUSED;
1951 }
1952 return VINF_SUCCESS;
1953}
1954
1955/**
1956 * @callback_method_impl{FNIOMIOPORTOUT}
1957 */
1958static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns,
1959 void *pvUser, RTIOPORT Port, uint32_t u32Val, unsigned cbVal)
1960{
1961 PAC97STATE pThis = (PAC97STATE)pvUser;
1962
1963 switch (cbVal)
1964 {
1965 case 1:
1966 {
1967 LogFlowFunc(("U nam writeb %#x <- %#x\n", Port, u32Val));
1968 pThis->cas = 0;
1969 break;
1970 }
1971
1972 case 2:
1973 {
1974 uint32_t index = Port - pThis->IOPortBase[0];
1975 pThis->cas = 0;
1976 switch (index)
1977 {
1978 case AC97_Reset:
1979 ichac97Reset(pThis->CTX_SUFF(pDevIns));
1980 break;
1981 case AC97_Powerdown_Ctrl_Stat:
1982 u32Val &= ~0xf;
1983 u32Val |= ichac97MixerGet(pThis, index) & 0xf;
1984 ichac97MixerSet(pThis, index, u32Val);
1985 break;
1986 case AC97_Master_Volume_Mute:
1987 if (pThis->uCodecModel == AC97_CODEC_AD1980)
1988 {
1989 if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_LOSEL)
1990 break; /* Register controls surround (rear), do nothing. */
1991 }
1992 ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME_MASTER, u32Val);
1993 break;
1994 case AC97_Headphone_Volume_Mute:
1995 if (pThis->uCodecModel == AC97_CODEC_AD1980)
1996 {
1997 if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_HPSEL)
1998 {
1999 /* Register controls PCM (front) outputs. */
2000 ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME_MASTER, u32Val);
2001 }
2002 }
2003 break;
2004 case AC97_PCM_Out_Volume_Mute:
2005 ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_FRONT, u32Val);
2006 break;
2007 case AC97_Line_In_Volume_Mute:
2008 ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_LINE_IN, u32Val);
2009 break;
2010 case AC97_Record_Select:
2011 ichac97RecordSelect(pThis, u32Val);
2012 break;
2013 case AC97_Vendor_ID1:
2014 case AC97_Vendor_ID2:
2015 LogFlowFunc(("Attempt to write vendor ID to %#x\n", u32Val));
2016 break;
2017 case AC97_Extended_Audio_ID:
2018 LogFlowFunc(("Attempt to write extended audio ID to %#x\n", u32Val));
2019 break;
2020 case AC97_Extended_Audio_Ctrl_Stat:
2021 if (!(u32Val & AC97_EACS_VRA))
2022 {
2023 ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate, 48000);
2024 ichac97StreamReInit(pThis, &pThis->StreamOut);
2025
2026 ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate, 48000);
2027 ichac97StreamReInit(pThis, &pThis->StreamLineIn);
2028 }
2029 if (!(u32Val & AC97_EACS_VRM))
2030 {
2031 ichac97MixerSet(pThis, AC97_MIC_ADC_Rate, 48000);
2032 ichac97StreamReInit(pThis, &pThis->StreamMicIn);
2033 }
2034 LogFlowFunc(("Setting extended audio control to %#x\n", u32Val));
2035 ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, u32Val);
2036 break;
2037 case AC97_PCM_Front_DAC_Rate:
2038 if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRA)
2039 {
2040 ichac97MixerSet(pThis, index, u32Val);
2041 LogFlowFunc(("Set front DAC rate to %RU32\n", u32Val));
2042 ichac97StreamReInit(pThis, &pThis->StreamOut);
2043 }
2044 else
2045 AssertMsgFailed(("Attempt to set front DAC rate to %RU32, but VRA is not set\n", u32Val));
2046 break;
2047 case AC97_MIC_ADC_Rate:
2048 if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRM)
2049 {
2050 ichac97MixerSet(pThis, index, u32Val);
2051 LogFlowFunc(("Set MIC ADC rate to %RU32\n", u32Val));
2052 ichac97StreamReInit(pThis, &pThis->StreamMicIn);
2053 }
2054 else
2055 AssertMsgFailed(("Attempt to set MIC ADC rate to %RU32, but VRM is not set\n", u32Val));
2056 break;
2057 case AC97_PCM_LR_ADC_Rate:
2058 if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRA)
2059 {
2060 ichac97MixerSet(pThis, index, u32Val);
2061 LogFlowFunc(("Set front LR ADC rate to %RU32\n", u32Val));
2062 ichac97StreamReInit(pThis, &pThis->StreamLineIn);
2063 }
2064 else
2065 AssertMsgFailed(("Attempt to set LR ADC rate to %RU32, but VRA is not set\n", u32Val));
2066 break;
2067 default:
2068 LogFlowFunc(("U nam writew %#x <- %#x\n", Port, u32Val));
2069 ichac97MixerSet(pThis, index, u32Val);
2070 break;
2071 }
2072 break;
2073 }
2074
2075 case 4:
2076 {
2077 LogFlowFunc(("U nam writel %#x <- %#x\n", Port, u32Val));
2078 pThis->cas = 0;
2079 break;
2080 }
2081
2082 default:
2083 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cbVal, u32Val));
2084 break;
2085 }
2086
2087 return VINF_SUCCESS;
2088}
2089
2090
2091/**
2092 * @callback_method_impl{FNPCIIOREGIONMAP}
2093 */
2094static DECLCALLBACK(int) ichac97IOPortMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb,
2095 PCIADDRESSSPACE enmType)
2096{
2097 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2098 PAC97STATE pThis = RT_FROM_MEMBER(pPciDev, AC97STATE, PciDev);
2099 RTIOPORT Port = (RTIOPORT)GCPhysAddress;
2100
2101 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2102 Assert(cb >= 0x20);
2103
2104 if (iRegion < 0 || iRegion > 1) /* We support 2 regions max. at the moment. */
2105 return VERR_INVALID_PARAMETER;
2106
2107 int rc;
2108 if (iRegion == 0)
2109 rc = PDMDevHlpIOPortRegister(pDevIns, Port, 256, pThis,
2110 ichac97IOPortNAMWrite, ichac97IOPortNAMRead,
2111 NULL, NULL, "ICHAC97 NAM");
2112 else
2113 rc = PDMDevHlpIOPortRegister(pDevIns, Port, 64, pThis,
2114 ichac97IOPortNABMWrite, ichac97IOPortNABMRead,
2115 NULL, NULL, "ICHAC97 NABM");
2116 if (RT_FAILURE(rc))
2117 return rc;
2118
2119 pThis->IOPortBase[iRegion] = Port;
2120 return VINF_SUCCESS;
2121}
2122
2123DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID)
2124{
2125 switch (uID)
2126 {
2127 case AC97SOUNDSOURCE_PI_INDEX: return &pThis->StreamLineIn;
2128 case AC97SOUNDSOURCE_MC_INDEX: return &pThis->StreamMicIn;
2129 case AC97SOUNDSOURCE_PO_INDEX: return &pThis->StreamOut;
2130 default: break;
2131 }
2132
2133 return NULL;
2134}
2135
2136#ifdef IN_RING3
2137static int ichac97SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStream)
2138{
2139 PAC97BMREGS pRegs = &pStream->Regs;
2140
2141 SSMR3PutU32(pSSM, pRegs->bdbar);
2142 SSMR3PutU8( pSSM, pRegs->civ);
2143 SSMR3PutU8( pSSM, pRegs->lvi);
2144 SSMR3PutU16(pSSM, pRegs->sr);
2145 SSMR3PutU16(pSSM, pRegs->picb);
2146 SSMR3PutU8( pSSM, pRegs->piv);
2147 SSMR3PutU8( pSSM, pRegs->cr);
2148 SSMR3PutS32(pSSM, pRegs->bd_valid);
2149 SSMR3PutU32(pSSM, pRegs->bd.addr);
2150 SSMR3PutU32(pSSM, pRegs->bd.ctl_len);
2151
2152 return VINF_SUCCESS;
2153}
2154
2155/**
2156 * @callback_method_impl{FNSSMDEVSAVEEXEC}
2157 */
2158static DECLCALLBACK(int) ichac97SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2159{
2160 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2161
2162 LogFlowFuncEnter();
2163
2164 SSMR3PutU32(pSSM, pThis->glob_cnt);
2165 SSMR3PutU32(pSSM, pThis->glob_sta);
2166 SSMR3PutU32(pSSM, pThis->cas);
2167
2168 /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
2169 /* Note: The order the streams are saved here is critical, so don't touch. */
2170 int rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StreamLineIn);
2171 AssertRC(rc2);
2172 rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StreamOut);
2173 AssertRC(rc2);
2174 rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StreamMicIn);
2175 AssertRC(rc2);
2176
2177 SSMR3PutMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
2178
2179 uint8_t active[AC97SOUNDSOURCE_LAST_INDEX];
2180
2181 active[AC97SOUNDSOURCE_PI_INDEX] = ichac97StreamIsActive(pThis, &pThis->StreamLineIn) ? 1 : 0;
2182 active[AC97SOUNDSOURCE_PO_INDEX] = ichac97StreamIsActive(pThis, &pThis->StreamOut) ? 1 : 0;
2183 active[AC97SOUNDSOURCE_MC_INDEX] = ichac97StreamIsActive(pThis, &pThis->StreamMicIn) ? 1 : 0;
2184
2185 SSMR3PutMem(pSSM, active, sizeof(active));
2186
2187 LogFlowFuncLeaveRC(VINF_SUCCESS);
2188 return VINF_SUCCESS;
2189}
2190
2191static int ichac97LoadStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStream)
2192{
2193 PAC97BMREGS pRegs = &pStream->Regs;
2194
2195 SSMR3GetU32(pSSM, &pRegs->bdbar);
2196 SSMR3GetU8( pSSM, &pRegs->civ);
2197 SSMR3GetU8( pSSM, &pRegs->lvi);
2198 SSMR3GetU16(pSSM, &pRegs->sr);
2199 SSMR3GetU16(pSSM, &pRegs->picb);
2200 SSMR3GetU8( pSSM, &pRegs->piv);
2201 SSMR3GetU8( pSSM, &pRegs->cr);
2202 SSMR3GetS32(pSSM, &pRegs->bd_valid);
2203 SSMR3GetU32(pSSM, &pRegs->bd.addr);
2204 SSMR3GetU32(pSSM, &pRegs->bd.ctl_len);
2205
2206 return VINF_SUCCESS;
2207}
2208
2209/**
2210 * @callback_method_impl{FNSSMDEVLOADEXEC}
2211 */
2212static DECLCALLBACK(int) ichac97LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2213{
2214 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2215
2216 LogRel2(("ichac97LoadExec: uVersion=%RU32, uPass=0x%x\n", uVersion, uPass));
2217
2218 AssertMsgReturn (uVersion == AC97_SSM_VERSION, ("%RU32\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
2219 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
2220
2221 SSMR3GetU32(pSSM, &pThis->glob_cnt);
2222 SSMR3GetU32(pSSM, &pThis->glob_sta);
2223 SSMR3GetU32(pSSM, &pThis->cas);
2224
2225 /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
2226 /* Note: The order the streams are loaded here is critical, so don't touch. */
2227 int rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StreamLineIn);
2228 AssertRC(rc2);
2229 rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StreamOut);
2230 AssertRC(rc2);
2231 rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StreamMicIn);
2232 AssertRC(rc2);
2233
2234 SSMR3GetMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
2235
2236 /** @todo r=andy Stream IDs are hardcoded to certain streams. */
2237 uint8_t uaStrmsActive[AC97SOUNDSOURCE_LAST_INDEX];
2238 SSMR3GetMem(pSSM, uaStrmsActive, sizeof(uaStrmsActive));
2239
2240 ichac97RecordSelect(pThis, ichac97MixerGet(pThis, AC97_Record_Select));
2241# define V_(a, b) ichac97MixerSetVolume(pThis, a, b, ichac97MixerGet(pThis, a))
2242 V_(AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER);
2243 V_(AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT);
2244 V_(AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN);
2245 V_(AC97_Mic_Volume_Mute, PDMAUDIOMIXERCTL_MIC_IN);
2246# undef V_
2247 if (pThis->uCodecModel == AC97_CODEC_AD1980)
2248 if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_HPSEL)
2249 ichac97MixerSetVolume(pThis, AC97_Headphone_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER,
2250 ichac97MixerGet(pThis, AC97_Headphone_Volume_Mute));
2251
2252 int rc = ichac97StreamsInit(pThis);
2253 if (RT_SUCCESS(rc))
2254 {
2255 /** @todo r=andy Stream IDs are hardcoded to certain streams. */
2256 rc = ichac97StreamSetActive(pThis, &pThis->StreamLineIn, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_PI_INDEX]));
2257 if (RT_SUCCESS(rc))
2258 rc = ichac97StreamSetActive(pThis, &pThis->StreamMicIn, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_MC_INDEX]));
2259 if (RT_SUCCESS(rc))
2260 rc = ichac97StreamSetActive(pThis, &pThis->StreamOut, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_PO_INDEX]));
2261 }
2262
2263 pThis->bup_flag = 0;
2264 pThis->last_samp = 0;
2265
2266 LogFlowFuncLeaveRC(rc);
2267 return rc;
2268}
2269
2270
2271/**
2272 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2273 */
2274static DECLCALLBACK(void *) ichac97QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
2275{
2276 PAC97STATE pThis = RT_FROM_MEMBER(pInterface, AC97STATE, IBase);
2277 Assert(&pThis->IBase == pInterface);
2278
2279 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2280 return NULL;
2281}
2282
2283
2284/**
2285 * Powers off the device.
2286 *
2287 * @param pDevIns Device instance to power off.
2288 */
2289static DECLCALLBACK(void) ichac97PowerOff(PPDMDEVINS pDevIns)
2290{
2291 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2292
2293 LogRel2(("AC97: Powering off ...\n"));
2294
2295 /**
2296 * Note: Destroy the mixer while powering off and *not* in ichac97Destruct,
2297 * giving the mixer the chance to release any references held to
2298 * PDM audio streams it maintains.
2299 */
2300 if (pThis->pMixer)
2301 {
2302 AudioMixerDestroy(pThis->pMixer);
2303 pThis->pMixer = NULL;
2304 }
2305}
2306
2307
2308/**
2309 * @interface_method_impl{PDMDEVREG,pfnReset}
2310 *
2311 * @remarks The original sources didn't install a reset handler, but it seems to
2312 * make sense to me so we'll do it.
2313 */
2314static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns)
2315{
2316 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2317
2318 LogFlowFuncEnter();
2319
2320 /*
2321 * Reset the device state (will need pDrv later).
2322 */
2323 ichac97StreamResetBMRegs(pThis, &pThis->StreamLineIn);
2324 ichac97StreamResetBMRegs(pThis, &pThis->StreamMicIn);
2325 ichac97StreamResetBMRegs(pThis, &pThis->StreamOut);
2326
2327 /*
2328 * Reset the mixer too. The Windows XP driver seems to rely on
2329 * this. At least it wants to read the vendor id before it resets
2330 * the codec manually.
2331 */
2332 ichac97MixerReset(pThis);
2333
2334 /*
2335 * Stop any audio currently playing and/or recording.
2336 */
2337 AudioMixerSinkCtl(pThis->pSinkOutput, AUDMIXSINKCMD_DISABLE);
2338 AudioMixerSinkCtl(pThis->pSinkMicIn, AUDMIXSINKCMD_DISABLE);
2339 AudioMixerSinkCtl(pThis->pSinkLineIn, AUDMIXSINKCMD_DISABLE);
2340
2341 /*
2342 * Reset all streams.
2343 */
2344 ichac97StreamReset(pThis, &pThis->StreamLineIn);
2345 ichac97StreamReset(pThis, &pThis->StreamMicIn);
2346 ichac97StreamReset(pThis, &pThis->StreamOut);
2347
2348 LogRel(("AC97: Reset\n"));
2349}
2350
2351
2352/**
2353 * @interface_method_impl{PDMDEVREG,pfnDestruct}
2354 */
2355static DECLCALLBACK(int) ichac97Destruct(PPDMDEVINS pDevIns)
2356{
2357 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2358
2359 LogFlowFuncEnter();
2360
2361 ichac97StreamDestroy(&pThis->StreamLineIn);
2362 ichac97StreamDestroy(&pThis->StreamMicIn);
2363 ichac97StreamDestroy(&pThis->StreamOut);
2364
2365 PAC97DRIVER pDrv, pDrvNext;
2366 RTListForEachSafe(&pThis->lstDrv, pDrv, pDrvNext, AC97DRIVER, Node)
2367 {
2368 RTListNodeRemove(&pDrv->Node);
2369 RTMemFree(pDrv);
2370 }
2371
2372 /* Sanity. */
2373 Assert(RTListIsEmpty(&pThis->lstDrv));
2374
2375 LogFlowFuncLeave();
2376 return VINF_SUCCESS;
2377}
2378
2379
2380/**
2381 * Attach command, internal version.
2382 *
2383 * This is called to let the device attach to a driver for a specified LUN
2384 * during runtime. This is not called during VM construction, the device
2385 * constructor has to attach to all the available drivers.
2386 *
2387 * @returns VBox status code.
2388 * @param pDevIns The device instance.
2389 * @param pDrv Driver to (re-)use for (re-)attaching to.
2390 * If NULL is specified, a new driver will be created and appended
2391 * to the driver list.
2392 * @param uLUN The logical unit which is being detached.
2393 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2394 */
2395static DECLCALLBACK(int) ichac97AttachInternal(PPDMDEVINS pDevIns, PAC97DRIVER pDrv, unsigned uLUN, uint32_t fFlags)
2396{
2397 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2398
2399 /*
2400 * Attach driver.
2401 */
2402 char *pszDesc = NULL;
2403 if (RTStrAPrintf(&pszDesc, "Audio driver port (AC'97) for LUN #%u", uLUN) <= 0)
2404 AssertReleaseMsgReturn(pszDesc,
2405 ("Not enough memory for AC'97 driver port description of LUN #%u\n", uLUN),
2406 VERR_NO_MEMORY);
2407
2408 PPDMIBASE pDrvBase;
2409 int rc = PDMDevHlpDriverAttach(pDevIns, uLUN,
2410 &pThis->IBase, &pDrvBase, pszDesc);
2411 if (RT_SUCCESS(rc))
2412 {
2413 if (pDrv == NULL)
2414 pDrv = (PAC97DRIVER)RTMemAllocZ(sizeof(AC97DRIVER));
2415 if (pDrv)
2416 {
2417 pDrv->pDrvBase = pDrvBase;
2418 pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
2419 AssertMsg(pDrv->pConnector != NULL, ("Configuration error: LUN #%u has no host audio interface, rc=%Rrc\n", uLUN, rc));
2420 pDrv->pAC97State = pThis;
2421 pDrv->uLUN = uLUN;
2422
2423 /*
2424 * For now we always set the driver at LUN 0 as our primary
2425 * host backend. This might change in the future.
2426 */
2427 if (pDrv->uLUN == 0)
2428 pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
2429
2430 LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
2431
2432 /* Attach to driver list if not attached yet. */
2433 if (!pDrv->fAttached)
2434 {
2435 RTListAppend(&pThis->lstDrv, &pDrv->Node);
2436 pDrv->fAttached = true;
2437 }
2438 }
2439 else
2440 rc = VERR_NO_MEMORY;
2441 }
2442 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2443 LogFunc(("No attached driver for LUN #%u\n", uLUN));
2444
2445 if (RT_FAILURE(rc))
2446 {
2447 /* Only free this string on failure;
2448 * must remain valid for the live of the driver instance. */
2449 RTStrFree(pszDesc);
2450 }
2451
2452 LogFunc(("iLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
2453 return rc;
2454}
2455
2456
2457/**
2458 * Attach command.
2459 *
2460 * This is called to let the device attach to a driver for a specified LUN
2461 * during runtime. This is not called during VM construction, the device
2462 * constructor has to attach to all the available drivers.
2463 *
2464 * @returns VBox status code.
2465 * @param pDevIns The device instance.
2466 * @param uLUN The logical unit which is being detached.
2467 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2468 */
2469static DECLCALLBACK(int) ichac97Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
2470{
2471 return ichac97AttachInternal(pDevIns, NULL /* pDrv */, uLUN, fFlags);
2472}
2473
2474static DECLCALLBACK(void) ichac97Detach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
2475{
2476 LogFunc(("iLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
2477}
2478
2479/**
2480 * Re-attach.
2481 *
2482 * @returns VBox status code.
2483 * @param pThis Device instance.
2484 * @param pDrv Driver instance used for attaching to.
2485 * If NULL is specified, a new driver will be created and appended
2486 * to the driver list.
2487 * @param uLUN The logical unit which is being re-detached.
2488 * @param pszDriver Driver name.
2489 */
2490static int ichac97Reattach(PAC97STATE pThis, PAC97DRIVER pDrv, uint8_t uLUN, const char *pszDriver)
2491{
2492 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2493 AssertPtrReturn(pszDriver, VERR_INVALID_POINTER);
2494
2495 PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
2496 PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
2497 PCFGMNODE pDev0 = CFGMR3GetChild(pRoot, "Devices/ichac97/0/");
2498
2499 /* Remove LUN branch. */
2500 CFGMR3RemoveNode(CFGMR3GetChildF(pDev0, "LUN#%u/", uLUN));
2501
2502 if (pDrv)
2503 {
2504 /* Re-use a driver instance => detach the driver before. */
2505 int rc = PDMDevHlpDriverDetach(pThis->pDevInsR3, PDMIBASE_2_PDMDRV(pDrv->pDrvBase), 0 /* fFlags */);
2506 if (RT_FAILURE(rc))
2507 return rc;
2508 }
2509
2510#define RC_CHECK() if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; }
2511
2512 int rc;
2513 do
2514 {
2515 PCFGMNODE pLunL0;
2516 rc = CFGMR3InsertNodeF(pDev0, &pLunL0, "LUN#%u/", uLUN); RC_CHECK();
2517 rc = CFGMR3InsertString(pLunL0, "Driver", "AUDIO"); RC_CHECK();
2518 rc = CFGMR3InsertNode(pLunL0, "Config/", NULL); RC_CHECK();
2519
2520 PCFGMNODE pLunL1, pLunL2;
2521 rc = CFGMR3InsertNode (pLunL0, "AttachedDriver/", &pLunL1); RC_CHECK();
2522 rc = CFGMR3InsertNode (pLunL1, "Config/", &pLunL2); RC_CHECK();
2523 rc = CFGMR3InsertString(pLunL1, "Driver", pszDriver); RC_CHECK();
2524
2525 rc = CFGMR3InsertString(pLunL2, "AudioDriver", pszDriver); RC_CHECK();
2526
2527 } while (0);
2528
2529 if (RT_SUCCESS(rc))
2530 rc = ichac97AttachInternal(pThis->pDevInsR3, pDrv, uLUN, 0 /* fFlags */);
2531
2532 LogFunc(("pThis=%p, uLUN=%u, pszDriver=%s, rc=%Rrc\n", pThis, uLUN, pszDriver, rc));
2533
2534#undef RC_CHECK
2535
2536 return rc;
2537}
2538
2539/**
2540 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2541 */
2542static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2543{
2544 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2545
2546 /* NB: This must be done *before* any possible failure (and running the destructor). */
2547 RTListInit(&pThis->lstDrv);
2548
2549 Assert(iInstance == 0);
2550 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2551
2552 /*
2553 * Validations.
2554 */
2555 if (!CFGMR3AreValuesValid(pCfg,
2556 "Codec\0"
2557 "TimerHz\0"))
2558 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2559 N_("Invalid configuration for the AC'97 device"));
2560
2561 /*
2562 * Read config data.
2563 */
2564 char szCodec[20];
2565 int rc = CFGMR3QueryStringDef(pCfg, "Codec", &szCodec[0], sizeof(szCodec), "STAC9700");
2566 if (RT_FAILURE(rc))
2567 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2568 N_("AC'97 configuration error: Querying \"Codec\" as string failed"));
2569
2570#ifndef VBOX_WITH_AUDIO_CALLBACKS
2571 uint16_t uTimerHz;
2572 rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, AC97_TIMER_HZ /* Default value, if not set. */);
2573 if (RT_FAILURE(rc))
2574 return PDMDEV_SET_ERROR(pDevIns, rc,
2575 N_("AC'97 configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
2576#endif
2577
2578 /*
2579 * The AD1980 codec (with corresponding PCI subsystem vendor ID) is whitelisted
2580 * in the Linux kernel; Linux makes no attempt to measure the data rate and assumes
2581 * 48 kHz rate, which is exactly what we need. Same goes for AD1981B.
2582 */
2583 bool fChipAD1980 = false;
2584 if (!strcmp(szCodec, "STAC9700"))
2585 pThis->uCodecModel = AC97_CODEC_STAC9700;
2586 else if (!strcmp(szCodec, "AD1980"))
2587 pThis->uCodecModel = AC97_CODEC_AD1980;
2588 else if (!strcmp(szCodec, "AD1981B"))
2589 pThis->uCodecModel = AC97_CODEC_AD1981B;
2590 else
2591 {
2592 return PDMDevHlpVMSetError(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, RT_SRC_POS,
2593 N_("AC'97 configuration error: The \"Codec\" value \"%s\" is unsupported"),
2594 szCodec);
2595 }
2596
2597 /*
2598 * Initialize data (most of it anyway).
2599 */
2600 pThis->pDevInsR3 = pDevIns;
2601 /* IBase */
2602 pThis->IBase.pfnQueryInterface = ichac97QueryInterface;
2603
2604 /* PCI Device (the assertions will be removed later) */
2605 PCIDevSetVendorId (&pThis->PciDev, 0x8086); /* 00 ro - intel. */ Assert(pThis->PciDev.config[0x00] == 0x86); Assert(pThis->PciDev.config[0x01] == 0x80);
2606 PCIDevSetDeviceId (&pThis->PciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */ Assert(pThis->PciDev.config[0x02] == 0x15); Assert(pThis->PciDev.config[0x03] == 0x24);
2607 PCIDevSetCommand (&pThis->PciDev, 0x0000); /* 04 rw,ro - pcicmd. */ Assert(pThis->PciDev.config[0x04] == 0x00); Assert(pThis->PciDev.config[0x05] == 0x00);
2608 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);
2609 PCIDevSetRevisionId (&pThis->PciDev, 0x01); /* 08 ro - rid. */ Assert(pThis->PciDev.config[0x08] == 0x01);
2610 PCIDevSetClassProg (&pThis->PciDev, 0x00); /* 09 ro - pi. */ Assert(pThis->PciDev.config[0x09] == 0x00);
2611 PCIDevSetClassSub (&pThis->PciDev, 0x01); /* 0a ro - scc; 01 == Audio. */ Assert(pThis->PciDev.config[0x0a] == 0x01);
2612 PCIDevSetClassBase (&pThis->PciDev, 0x04); /* 0b ro - bcc; 04 == multimedia. */ Assert(pThis->PciDev.config[0x0b] == 0x04);
2613 PCIDevSetHeaderType (&pThis->PciDev, 0x00); /* 0e ro - headtyp. */ Assert(pThis->PciDev.config[0x0e] == 0x00);
2614 PCIDevSetBaseAddress (&pThis->PciDev, 0, /* 10 rw - nambar - native audio mixer base. */
2615 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);
2616 PCIDevSetBaseAddress (&pThis->PciDev, 1, /* 14 rw - nabmbar - native audio bus mastering. */
2617 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);
2618 PCIDevSetInterruptLine (&pThis->PciDev, 0x00); /* 3c rw. */ Assert(pThis->PciDev.config[0x3c] == 0x00);
2619 PCIDevSetInterruptPin (&pThis->PciDev, 0x01); /* 3d ro - INTA#. */ Assert(pThis->PciDev.config[0x3d] == 0x01);
2620
2621 if (pThis->uCodecModel == AC97_CODEC_AD1980)
2622 {
2623 PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x1028); /* 2c ro - Dell.) */
2624 PCIDevSetSubSystemId (&pThis->PciDev, 0x0177); /* 2e ro. */
2625 }
2626 else if (pThis->uCodecModel == AC97_CODEC_AD1981B)
2627 {
2628 PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x1028); /* 2c ro - Dell.) */
2629 PCIDevSetSubSystemId (&pThis->PciDev, 0x01ad); /* 2e ro. */
2630 }
2631 else
2632 {
2633 PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x8086); /* 2c ro - Intel.) */
2634 PCIDevSetSubSystemId (&pThis->PciDev, 0x0000); /* 2e ro. */
2635 }
2636
2637 /*
2638 * Register the PCI device, it's I/O regions, the timer and the
2639 * saved state item.
2640 */
2641 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
2642 if (RT_FAILURE(rc))
2643 return rc;
2644
2645 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 256, PCI_ADDRESS_SPACE_IO, ichac97IOPortMap);
2646 if (RT_FAILURE(rc))
2647 return rc;
2648
2649 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 64, PCI_ADDRESS_SPACE_IO, ichac97IOPortMap);
2650 if (RT_FAILURE(rc))
2651 return rc;
2652
2653 rc = PDMDevHlpSSMRegister(pDevIns, AC97_SSM_VERSION, sizeof(*pThis), ichac97SaveExec, ichac97LoadExec);
2654 if (RT_FAILURE(rc))
2655 return rc;
2656
2657 /*
2658 * Attach driver.
2659 */
2660 uint8_t uLUN;
2661 for (uLUN = 0; uLUN < UINT8_MAX; ++uLUN)
2662 {
2663 LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
2664 rc = ichac97AttachInternal(pDevIns, NULL /* pDrv */, uLUN, 0 /* fFlags */);
2665 if (RT_FAILURE(rc))
2666 {
2667 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2668 rc = VINF_SUCCESS;
2669 else if (rc == VERR_AUDIO_BACKEND_INIT_FAILED)
2670 {
2671 ichac97Reattach(pThis, NULL /* pDrv */, uLUN, "NullAudio");
2672 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2673 N_("No audio devices could be opened. Selecting the NULL audio backend "
2674 "with the consequence that no sound is audible"));
2675 /* attaching to the NULL audio backend will never fail */
2676 rc = VINF_SUCCESS;
2677 }
2678 break;
2679 }
2680 }
2681
2682 LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
2683
2684 if (RT_SUCCESS(rc))
2685 {
2686 rc = AudioMixerCreate("AC'97 Mixer", 0 /* uFlags */, &pThis->pMixer);
2687 if (RT_SUCCESS(rc))
2688 {
2689 /* Set a default audio format for our mixer. */
2690 PDMAUDIOSTREAMCFG streamCfg;
2691 streamCfg.uHz = 44100;
2692 streamCfg.cChannels = 2;
2693 streamCfg.enmFormat = PDMAUDIOFMT_S16;
2694 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
2695
2696 rc = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
2697 AssertRC(rc);
2698
2699 /* Add all required audio sinks. */
2700 int rc2 = AudioMixerCreateSink(pThis->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
2701 AssertRC(rc2);
2702
2703 rc2 = AudioMixerCreateSink(pThis->pMixer, "[Recording] Line In", AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
2704 AssertRC(rc2);
2705
2706 rc2 = AudioMixerCreateSink(pThis->pMixer, "[Recording] Microphone In", AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn);
2707 AssertRC(rc2);
2708 }
2709 }
2710
2711 ichac97Reset(pDevIns);
2712
2713 if (RT_SUCCESS(rc))
2714 {
2715 ichac97StreamsInit(pThis);
2716
2717 PAC97DRIVER pDrv;
2718 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
2719 {
2720 /*
2721 * Only primary drivers are critical for the VM to run. Everything else
2722 * might not worth showing an own error message box in the GUI.
2723 */
2724 if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
2725 continue;
2726
2727 PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
2728 AssertPtr(pCon);
2729
2730 bool fValidLineIn = AudioMixerStreamIsValid(pDrv->LineIn.pMixStrm);
2731 bool fValidMicIn = AudioMixerStreamIsValid(pDrv->MicIn.pMixStrm);
2732 bool fValidOut = AudioMixerStreamIsValid(pDrv->Out.pMixStrm);
2733
2734 if ( !fValidLineIn
2735 && !fValidMicIn
2736 && !fValidOut)
2737 {
2738 LogRel(("AC97: Falling back to NULL backend (no sound audible)\n"));
2739
2740 /* Destroy the streams before re-attaching the NULL driver. */
2741 ichac97StreamsDestroy(pThis);
2742
2743 ichac97Reset(pDevIns);
2744 ichac97Reattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
2745
2746 ichac97StreamsInit(pThis);
2747
2748 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2749 N_("No audio devices could be opened. Selecting the NULL audio backend "
2750 "with the consequence that no sound is audible"));
2751 }
2752 else
2753 {
2754 bool fWarn = false;
2755
2756 PDMAUDIOBACKENDCFG backendCfg;
2757 int rc2 = pCon->pfnGetConfig(pCon, &backendCfg);
2758 if (RT_SUCCESS(rc2))
2759 {
2760 if (backendCfg.cSources)
2761 {
2762 /* If the audio backend supports two or more input streams at once,
2763 * warn if one of our two inputs (microphone-in and line-in) failed to initialize. */
2764 if (backendCfg.cMaxStreamsIn >= 2)
2765 fWarn = !fValidLineIn || !fValidMicIn;
2766 /* If the audio backend only supports one input stream at once (e.g. pure ALSA, and
2767 * *not* ALSA via PulseAudio plugin!), only warn if both of our inputs failed to initialize.
2768 * One of the two simply is not in use then. */
2769 else if (backendCfg.cMaxStreamsIn == 1)
2770 fWarn = !fValidLineIn && !fValidMicIn;
2771 /* Don't warn if our backend is not able of supporting any input streams at all. */
2772 }
2773
2774 if ( !fWarn
2775 && backendCfg.cSinks)
2776 {
2777 fWarn = !fValidOut;
2778 }
2779 }
2780 else
2781 {
2782 LogRel(("AC97: Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n", pDrv->uLUN, rc2));
2783 fWarn = true;
2784 }
2785
2786 if (fWarn)
2787 {
2788 char szMissingStreams[255] = "";
2789 size_t len = 0;
2790 if (!fValidLineIn)
2791 {
2792 LogRel(("AC97: WARNING: Unable to open PCM line input for LUN #%RU8!\n", pDrv->uLUN));
2793 len = RTStrPrintf(szMissingStreams, sizeof(szMissingStreams), "PCM Input");
2794 }
2795 if (!fValidMicIn)
2796 {
2797 LogRel(("AC97: WARNING: Unable to open PCM microphone input for LUN #%RU8!\n", pDrv->uLUN));
2798 len += RTStrPrintf(szMissingStreams + len,
2799 sizeof(szMissingStreams) - len, len ? ", PCM Microphone" : "PCM Microphone");
2800 }
2801 if (!fValidOut)
2802 {
2803 LogRel(("AC97: WARNING: Unable to open PCM output for LUN #%RU8!\n", pDrv->uLUN));
2804 len += RTStrPrintf(szMissingStreams + len,
2805 sizeof(szMissingStreams) - len, len ? ", PCM Output" : "PCM Output");
2806 }
2807
2808 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2809 N_("Some AC'97 audio streams (%s) could not be opened. Guest applications generating audio "
2810 "output or depending on audio input may hang. Make sure your host audio device "
2811 "is working properly. Check the logfile for error messages of the audio "
2812 "subsystem"), szMissingStreams);
2813 }
2814 }
2815 }
2816 }
2817
2818# ifndef VBOX_WITH_AUDIO_CALLBACKS
2819 if (RT_SUCCESS(rc))
2820 {
2821 /* Start the emulation timer. */
2822 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ichac97Timer, pThis,
2823 TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchAc97", &pThis->pTimer);
2824 AssertRCReturn(rc, rc);
2825
2826 if (RT_SUCCESS(rc))
2827 {
2828 pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimer) / uTimerHz;
2829 pThis->uTimerTS = TMTimerGet(pThis->pTimer);
2830 LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
2831
2832 ichac97TimerMaybeStart(pThis);
2833 }
2834 }
2835# else
2836 if (RT_SUCCESS(rc))
2837 {
2838 PAC97DRIVER pDrv;
2839 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
2840 {
2841 /* Only register primary driver.
2842 * The device emulation does the output multiplexing then. */
2843 if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
2844 continue;
2845
2846 PDMAUDIOCALLBACK AudioCallbacks[2];
2847
2848 AC97CALLBACKCTX Ctx = { pThis, pDrv };
2849
2850 AudioCallbacks[0].enmType = PDMAUDIOCALLBACKTYPE_INPUT;
2851 AudioCallbacks[0].pfnCallback = ac97CallbackInput;
2852 AudioCallbacks[0].pvCtx = &Ctx;
2853 AudioCallbacks[0].cbCtx = sizeof(AC97CALLBACKCTX);
2854
2855 AudioCallbacks[1].enmType = PDMAUDIOCALLBACKTYPE_OUTPUT;
2856 AudioCallbacks[1].pfnCallback = ac97CallbackOutput;
2857 AudioCallbacks[1].pvCtx = &Ctx;
2858 AudioCallbacks[1].cbCtx = sizeof(AC97CALLBACKCTX);
2859
2860 rc = pDrv->pConnector->pfnRegisterCallbacks(pDrv->pConnector, AudioCallbacks, RT_ELEMENTS(AudioCallbacks));
2861 if (RT_FAILURE(rc))
2862 break;
2863 }
2864 }
2865# endif
2866
2867# ifdef VBOX_WITH_STATISTICS
2868 if (RT_SUCCESS(rc))
2869 {
2870 /*
2871 * Register statistics.
2872 */
2873 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer, STAMTYPE_PROFILE, "/Devices/AC97/Timer", STAMUNIT_TICKS_PER_CALL, "Profiling ichac97Timer.");
2874 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, "/Devices/AC97/BytesRead" , STAMUNIT_BYTES, "Bytes read from AC97 emulation.");
2875 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "/Devices/AC97/BytesWritten", STAMUNIT_BYTES, "Bytes written to AC97 emulation.");
2876 }
2877# endif
2878
2879 LogFlowFuncLeaveRC(rc);
2880 return rc;
2881}
2882
2883/**
2884 * The device registration structure.
2885 */
2886const PDMDEVREG g_DeviceICHAC97 =
2887{
2888 /* u32Version */
2889 PDM_DEVREG_VERSION,
2890 /* szName */
2891 "ichac97",
2892 /* szRCMod */
2893 "",
2894 /* szR0Mod */
2895 "",
2896 /* pszDescription */
2897 "ICH AC'97 Audio Controller",
2898 /* fFlags */
2899 PDM_DEVREG_FLAGS_DEFAULT_BITS,
2900 /* fClass */
2901 PDM_DEVREG_CLASS_AUDIO,
2902 /* cMaxInstances */
2903 1,
2904 /* cbInstance */
2905 sizeof(AC97STATE),
2906 /* pfnConstruct */
2907 ichac97Construct,
2908 /* pfnDestruct */
2909 ichac97Destruct,
2910 /* pfnRelocate */
2911 NULL,
2912 /* pfnMemSetup */
2913 NULL,
2914 /* pfnPowerOn */
2915 NULL,
2916 /* pfnReset */
2917 ichac97Reset,
2918 /* pfnSuspend */
2919 NULL,
2920 /* pfnResume */
2921 NULL,
2922 /* pfnAttach */
2923 ichac97Attach,
2924 /* pfnDetach */
2925 ichac97Detach,
2926 /* pfnQueryInterface. */
2927 NULL,
2928 /* pfnInitComplete */
2929 NULL,
2930 /* pfnPowerOff */
2931 ichac97PowerOff,
2932 /* pfnSoftReset */
2933 NULL,
2934 /* u32VersionEnd */
2935 PDM_DEVREG_VERSION
2936};
2937
2938#endif /* !IN_RING3 */
2939#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

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