VirtualBox

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

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

Audio/DevIchAc97.cpp: Check the stream's status register if a device stream state change actually is required.

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