VirtualBox

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

Last change on this file since 61177 was 61167, checked in by vboxsync, 9 years ago

Audio: Renaming.

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

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