VirtualBox

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

Last change on this file since 63927 was 63863, checked in by vboxsync, 9 years ago

Build fix.

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

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