VirtualBox

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

Last change on this file since 55920 was 55920, checked in by vboxsync, 10 years ago

PDM/Audio: AudioMixBuffer documentation, renaming.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 89.7 KB
Line 
1/* $Id: DevIchAc97.cpp 55920 2015-05-18 19:11:51Z vboxsync $ */
2/** @file
3 * DevIchAc97 - VBox ICH AC97 Audio Controller.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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* Header Files *
20*******************************************************************************/
21#include <VBox/vmm/pdmdev.h>
22#include <VBox/vmm/pdmaudioifs.h>
23
24#include <iprt/assert.h>
25#ifdef IN_RING3
26# include <iprt/mem.h>
27# include <iprt/string.h>
28# include <iprt/uuid.h>
29#endif
30
31#include "VBoxDD.h"
32
33#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
34# include "AudioMixer.h"
35#else
36 extern "C" {
37 #include "audio.h"
38 }
39#endif
40
41#ifdef LOG_GROUP
42 #undef LOG_GROUP
43#endif
44#define LOG_GROUP LOG_GROUP_DEV_AUDIO
45#include <VBox/log.h>
46
47/*******************************************************************************
48* Defined Constants And Macros *
49*******************************************************************************/
50#undef LOG_VOICES
51
52#ifdef DEBUG
53//#define DEBUG_LUN
54# ifdef DEBUG_LUN
55# define DEBUG_LUN_NUM 1
56# endif
57#endif /* DEBUG */
58
59#define AC97_SSM_VERSION 1
60
61#ifdef VBOX
62# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
63# define SOFT_VOLUME /** @todo Get rid of this crap. */
64# else
65# undef SOFT_VOLUME
66# endif
67#else
68# define SOFT_VOLUME
69#endif
70
71#define SR_FIFOE RT_BIT(4) /* rwc, fifo error */
72#define SR_BCIS RT_BIT(3) /* rwc, buffer completion interrupt status */
73#define SR_LVBCI RT_BIT(2) /* rwc, last valid buffer completion interrupt */
74#define SR_CELV RT_BIT(1) /* ro, current equals last valid */
75#define SR_DCH RT_BIT(0) /* ro, controller halted */
76#define SR_VALID_MASK (RT_BIT(5) - 1)
77#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
78#define SR_RO_MASK (SR_DCH | SR_CELV)
79#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
80
81#define CR_IOCE RT_BIT(4) /* rw */
82#define CR_FEIE RT_BIT(3) /* rw */
83#define CR_LVBIE RT_BIT(2) /* rw */
84#define CR_RR RT_BIT(1) /* rw */
85#define CR_RPBM RT_BIT(0) /* rw */
86#define CR_VALID_MASK (RT_BIT(5) - 1)
87#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
88
89#define GC_WR 4 /* rw */
90#define GC_CR 2 /* rw */
91#define GC_VALID_MASK (RT_BIT(6) - 1)
92
93#define GS_MD3 RT_BIT(17) /* rw */
94#define GS_AD3 RT_BIT(16) /* rw */
95#define GS_RCS RT_BIT(15) /* rwc */
96#define GS_B3S12 RT_BIT(14) /* ro */
97#define GS_B2S12 RT_BIT(13) /* ro */
98#define GS_B1S12 RT_BIT(12) /* ro */
99#define GS_S1R1 RT_BIT(11) /* rwc */
100#define GS_S0R1 RT_BIT(10) /* rwc */
101#define GS_S1CR RT_BIT(9) /* ro */
102#define GS_S0CR RT_BIT(8) /* ro */
103#define GS_MINT RT_BIT(7) /* ro */
104#define GS_POINT RT_BIT(6) /* ro */
105#define GS_PIINT RT_BIT(5) /* ro */
106#define GS_RSRVD (RT_BIT(4)|RT_BIT(3))
107#define GS_MOINT RT_BIT(2) /* ro */
108#define GS_MIINT RT_BIT(1) /* ro */
109#define GS_GSCI RT_BIT(0) /* rwc */
110#define GS_RO_MASK (GS_B3S12 | \
111 GS_B2S12 | \
112 GS_B1S12 | \
113 GS_S1CR | \
114 GS_S0CR | \
115 GS_MINT | \
116 GS_POINT | \
117 GS_PIINT | \
118 GS_RSRVD | \
119 GS_MOINT | \
120 GS_MIINT)
121#define GS_VALID_MASK (RT_BIT(18) - 1)
122#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
123
124/** @name Buffer Descriptor
125 * @{ */
126#define BD_IOC RT_BIT(31) /**< Interrupt on Completion */
127#define BD_BUP RT_BIT(30) /**< Buffer Underrun Policy */
128/** @} */
129
130#define EACS_VRA 1
131#define EACS_VRM 8
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_Vendor_ID1 = 0x7c,
182 AC97_Vendor_ID2 = 0x7e
183};
184
185
186/*******************************************************************************
187* Structures and Typedefs *
188*******************************************************************************/
189/**
190 * Buffer descriptor.
191 */
192typedef struct BD
193{
194 uint32_t addr;
195 uint32_t ctl_len;
196} BD;
197
198typedef struct AC97BusMasterRegs
199{
200 uint32_t bdbar; /**< rw 0, buffer descriptor list base address register */
201 uint8_t civ; /**< ro 0, current index value */
202 uint8_t lvi; /**< rw 0, last valid index */
203 uint16_t sr; /**< rw 1, status register */
204 uint16_t picb; /**< ro 0, position in current buffer */
205 uint8_t piv; /**< ro 0, prefetched index value */
206 uint8_t cr; /**< rw 0, control register */
207 int bd_valid; /**< initialized? */
208 BD bd; /**< buffer descriptor */
209} AC97BusMasterRegs;
210/** Pointer to a AC97 bus master register. */
211typedef AC97BusMasterRegs *PAC97BMREG;
212
213#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
214typedef struct AC97INPUTSTREAM
215{
216 /** PCM line input stream. */
217 R3PTRTYPE(PPDMAUDIOGSTSTRMIN) pStrmIn;
218 /** Mixer handle for line input stream. */
219 R3PTRTYPE(PAUDMIXSTREAM) phStrmIn;
220} AC97INPUTSTREAM, *PAC97INPUTSTREAM;
221
222typedef struct AC97OUTPUTSTREAM
223{
224 /** PCM output stream. */
225 R3PTRTYPE(PPDMAUDIOGSTSTRMOUT) pStrmOut;
226 /** Mixer handle for output stream. */
227 R3PTRTYPE(PAUDMIXSTREAM) phStrmOut;
228} AC97OUTPUTSTREAM, *PAC97OUTPUTSTREAM;
229
230/**
231 * Struct for maintaining a host backend driver.
232 */
233typedef struct AC97STATE *PAC97STATE;
234typedef struct AC97DRIVER
235{
236 union
237 {
238 /** Node for storing this driver in our device driver
239 * list of AC97STATE. */
240 RTLISTNODE Node;
241 struct
242 {
243 R3PTRTYPE(void *) dummy1;
244 R3PTRTYPE(void *) dummy2;
245 } dummy;
246 };
247
248 /** Pointer to AC97 controller (state). */
249 R3PTRTYPE(PAC97STATE) pAC97State;
250 /** Driver flags. */
251 PDMAUDIODRVFLAGS Flags;
252 uint32_t PaddingFlags;
253 /** LUN # to which this driver has been assigned. */
254 uint8_t uLUN;
255 uint8_t Padding[5];
256 /** Audio connector interface to the underlying
257 * host backend. */
258 R3PTRTYPE(PPDMIAUDIOCONNECTOR) pConnector;
259 /** Stream for line input. */
260 AC97INPUTSTREAM LineIn;
261 /** Stream for mic input. */
262 AC97INPUTSTREAM MicIn;
263 /** Stream for output. */
264 AC97OUTPUTSTREAM Out;
265} AC97DRIVER, *PAC97DRIVER;
266#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
267
268typedef struct AC97STATE
269{
270 /** The PCI device state. */
271 PCIDevice PciDev;
272 /** Global Control (Bus Master Control Register) */
273 uint32_t glob_cnt;
274 /** Global Status (Bus Master Control Register) */
275 uint32_t glob_sta;
276 /** Codec Access Semaphore Register (Bus Master Control Register) */
277 uint32_t cas;
278 uint32_t last_samp;
279 /** Bus Master Control Registers for PCM in, PCM out, and Mic in */
280 AC97BusMasterRegs bm_regs[3];
281 uint8_t mixer_data[256];
282#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
283 /** The emulation timer for handling the attached
284 * LUN drivers. */
285 PTMTIMERR3 pTimer;
286 /** Timer ticks for handling the LUN drivers. */
287 uint64_t uTicks;
288# ifdef VBOX_WITH_STATISTICS
289 STAMPROFILE StatTimer;
290 STAMCOUNTER StatBytesRead;
291 STAMCOUNTER StatBytesWritten;
292# endif
293 /** List of associated LUN drivers. */
294 RTLISTANCHOR lstDrv;
295 /** The device' software mixer. */
296 R3PTRTYPE(PAUDIOMIXER) pMixer;
297 /** Audio sink for PCM output. */
298 R3PTRTYPE(PAUDMIXSINK) pSinkOutput;
299 /** Audio sink for line input. */
300 R3PTRTYPE(PAUDMIXSINK) pSinkLineIn;
301 /** Audio sink for microphone input. */
302 R3PTRTYPE(PAUDMIXSINK) pSinkMicIn;
303#else
304 QEMUSoundCard card;
305 /** PCM in */
306 SWVoiceIn *voice_pi;
307 /** PCM out */
308 SWVoiceOut *voice_po;
309 /** Mic in */
310 SWVoiceIn *voice_mc;
311#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
312 uint8_t silence[128];
313 int bup_flag;
314 /** Pointer to the device instance. */
315 PPDMDEVINSR3 pDevIns;
316 /** Pointer to the attached audio driver. */
317 PPDMIBASE pDrvBase;
318 /** The base interface for LUN\#0. */
319 PDMIBASE IBase;
320 /** Base port of the I/O space region. */
321 RTIOPORT IOPortBase[2];
322 /** Pointer to temporary scratch read/write buffer. */
323 R3PTRTYPE(uint8_t *) pvReadWriteBuf;
324 /** Size of the temporary scratch read/write buffer. */
325 uint32_t cbReadWriteBuf;
326} AC97STATE;
327/** Pointer to the AC97 device state. */
328typedef AC97STATE *PAC97STATE;
329
330#ifndef VBOX_DEVICE_STRUCT_TESTCASE
331
332#define ICHAC97STATE_2_DEVINS(a_pAC97) ((a_pAC97)->pDevIns)
333
334enum
335{
336 BUP_SET = RT_BIT(0),
337 BUP_LAST = RT_BIT(1)
338};
339
340#define MKREGS(prefix, start) \
341 enum { \
342 prefix ## _BDBAR = start, \
343 prefix ## _CIV = start + 4, \
344 prefix ## _LVI = start + 5, \
345 prefix ## _SR = start + 6, \
346 prefix ## _PICB = start + 8, \
347 prefix ## _PIV = start + 10, \
348 prefix ## _CR = start + 11 \
349 }
350
351enum
352{
353 PI_INDEX = 0, /* PCM in */
354 PO_INDEX, /* PCM out */
355 MC_INDEX, /* Mic in */
356 LAST_INDEX
357};
358
359MKREGS (PI, PI_INDEX * 16);
360MKREGS (PO, PO_INDEX * 16);
361MKREGS (MC, MC_INDEX * 16);
362
363enum
364{
365 GLOB_CNT = 0x2c,
366 GLOB_STA = 0x30,
367 CAS = 0x34
368};
369
370#define GET_BM(a_idx) ( ((a_idx) >> 4) & 3 )
371
372#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
373static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
374static int ichac97TransferAudio(PAC97STATE pThis, int index, uint32_t cbElapsed);
375#else
376static void ichac97OutputCallback(void *pvContext, int cbFree);
377static void ichac97InputCallback(void *pvContext, int cbAvail);
378static void ichac97MicInCallback(void *pvContext, int cbAvail);
379#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
380
381static void ichac97WarmReset(PAC97STATE pThis)
382{
383 NOREF(pThis);
384}
385
386static void ichac97ColdReset(PAC97STATE pThis)
387{
388 NOREF(pThis);
389}
390
391/** Fetches the buffer descriptor at _CIV. */
392static void ichac97FetchBufDesc(PAC97STATE pThis, PAC97BMREG pReg)
393{
394 PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
395 uint32_t u32[2];
396
397 PDMDevHlpPhysRead(pDevIns, pReg->bdbar + pReg->civ * 8, &u32[0], sizeof(u32));
398 pReg->bd_valid = 1;
399#if !defined(RT_ARCH_X86) && !defined(RT_ARCH_AMD64)
400# error Please adapt the code (audio buffers are little endian)!
401#else
402 pReg->bd.addr = RT_H2LE_U32(u32[0] & ~3);
403 pReg->bd.ctl_len = RT_H2LE_U32(u32[1]);
404#endif
405 pReg->picb = pReg->bd.ctl_len & 0xffff;
406 LogFlowFunc(("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
407 pReg->civ, pReg->bd.addr, pReg->bd.ctl_len >> 16,
408 pReg->bd.ctl_len & 0xffff, (pReg->bd.ctl_len & 0xffff) << 1));
409}
410
411/**
412 * Update the BM status register
413 */
414static void ichac97UpdateStatus(PAC97STATE pThis, PAC97BMREG pReg, uint32_t new_sr)
415{
416 PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
417 int event = 0;
418 int level = 0;
419 uint32_t new_mask = new_sr & SR_INT_MASK;
420 uint32_t old_mask = pReg->sr & SR_INT_MASK;
421 static uint32_t const masks[] = { GS_PIINT, GS_POINT, GS_MINT };
422
423 if (new_mask ^ old_mask)
424 {
425 /** @todo is IRQ deasserted when only one of status bits is cleared? */
426 if (!new_mask)
427 {
428 event = 1;
429 level = 0;
430 }
431 else if ((new_mask & SR_LVBCI) && (pReg->cr & CR_LVBIE))
432 {
433 event = 1;
434 level = 1;
435 }
436 else if ((new_mask & SR_BCIS) && (pReg->cr & CR_IOCE))
437 {
438 event = 1;
439 level = 1;
440 }
441 }
442
443 pReg->sr = new_sr;
444
445 LogFlowFunc(("IOC%d LVB%d sr=%#x event=%d level=%d\n",
446 pReg->sr & SR_BCIS, pReg->sr & SR_LVBCI, pReg->sr, event, level));
447
448 if (event)
449 {
450 if (level)
451 pThis->glob_sta |= masks[pReg - pThis->bm_regs];
452 else
453 pThis->glob_sta &= ~masks[pReg - pThis->bm_regs];
454
455 LogFlowFunc(("set irq level=%d\n", !!level));
456 PDMDevHlpPCISetIrq(pDevIns, 0, !!level);
457 }
458}
459
460static void ichac97StreamSetActive(PAC97STATE pThis, int bm_index, int on)
461{
462 AssertPtrReturnVoid(pThis);
463
464 LogFlowFunc(("index=%d, on=%d\n", bm_index, on));
465
466#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
467 PAC97DRIVER pDrv;
468 switch (bm_index)
469 {
470 case PI_INDEX:
471 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
472 pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
473 pDrv->LineIn.pStrmIn, RT_BOOL(on));
474 break;
475
476 case PO_INDEX:
477 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
478 pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
479 pDrv->Out.pStrmOut, RT_BOOL(on));
480 break;
481
482 case MC_INDEX:
483 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
484 pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
485 pDrv->MicIn.pStrmIn, RT_BOOL(on));
486 break;
487
488 default:
489 AssertMsgFailed(("Wrong index %d\n", bm_index));
490 break;
491 }
492#else
493 switch (bm_index)
494 {
495 case PI_INDEX: AUD_set_active_in( pThis->voice_pi, on); break;
496 case PO_INDEX: AUD_set_active_out(pThis->voice_po, on); break;
497 case MC_INDEX: AUD_set_active_in( pThis->voice_mc, on); break;
498 default: AssertFailed (); break;
499 }
500#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
501}
502
503static void ichac97ResetBMRegs(PAC97STATE pThis, PAC97BMREG pReg)
504{
505 LogFlowFunc(("reset_bm_regs\n"));
506 pReg->bdbar = 0;
507 pReg->civ = 0;
508 pReg->lvi = 0;
509 /** @todo do we need to do that? */
510 ichac97UpdateStatus(pThis, pReg, SR_DCH);
511 pReg->picb = 0;
512 pReg->piv = 0;
513 pReg->cr = pReg->cr & CR_DONT_CLEAR_MASK;
514 pReg->bd_valid = 0;
515 ichac97StreamSetActive(pThis, pReg - pThis->bm_regs, 0);
516 RT_ZERO(pThis->silence);
517}
518
519static void ichac97MixerStore(PAC97STATE pThis, uint32_t i, uint16_t v)
520{
521 if (i + 2 > sizeof(pThis->mixer_data))
522 {
523 LogFlowFunc(("mixer_store: index %d out of bounds %d\n", i, sizeof(pThis->mixer_data)));
524 return;
525 }
526
527 pThis->mixer_data[i + 0] = v & 0xff;
528 pThis->mixer_data[i + 1] = v >> 8;
529}
530
531static uint16_t ichac97MixerLoad(PAC97STATE pThis, uint32_t i)
532{
533 uint16_t val;
534
535 if (i + 2 > sizeof(pThis->mixer_data))
536 {
537 LogFlowFunc(("mixer_store: index %d out of bounds %d\n", i, sizeof(pThis->mixer_data)));
538 val = 0xffff;
539 }
540 else
541 val = pThis->mixer_data[i + 0] | (pThis->mixer_data[i + 1] << 8);
542
543 return val;
544}
545
546static void ichac97OpenStream(PAC97STATE pThis, int index, uint16_t freq)
547{
548 LogFlowFunc(("index=%d, freq=%RU16\n", index, freq));
549
550 int rc;
551
552#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
553 PAC97DRIVER pDrv;
554 uint8_t uLUN = 0;
555
556 if (freq)
557 {
558 PDMAUDIOSTREAMCFG streamCfg;
559 RT_ZERO(streamCfg);
560 streamCfg.uHz = freq;
561 streamCfg.cChannels = 2;
562 streamCfg.enmFormat = AUD_FMT_S16;
563 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
564
565 char *pszDesc;
566
567 switch (index)
568 {
569 case PI_INDEX: /* Line input. */
570 {
571 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
572 {
573 if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] ac97.pi", uLUN) <= 0)
574 {
575 rc = VERR_NO_MEMORY;
576 break;
577 }
578
579 rc = pDrv->pConnector->pfnOpenIn(pDrv->pConnector,
580 pszDesc, PDMAUDIORECSOURCE_LINE_IN, &streamCfg, &pDrv->LineIn.pStrmIn);
581 LogFlowFunc(("LUN#%RU8: Opened line input with rc=%Rrc\n", uLUN, rc));
582 if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
583 {
584 AudioMixerRemoveStream(pThis->pSinkLineIn, pDrv->LineIn.phStrmIn);
585 rc = AudioMixerAddStreamIn(pThis->pSinkLineIn,
586 pDrv->pConnector, pDrv->LineIn.pStrmIn,
587 0 /* uFlags */,
588 &pDrv->LineIn.phStrmIn);
589 }
590
591 RTStrFree(pszDesc);
592 uLUN++;
593 }
594 break;
595 }
596
597 case PO_INDEX: /* Output. */
598 {
599 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
600 {
601 if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] ac97.po", uLUN) <= 0)
602 {
603 rc = VERR_NO_MEMORY;
604 break;
605 }
606
607 rc = pDrv->pConnector->pfnOpenOut(pDrv->pConnector, pszDesc, &streamCfg, &pDrv->Out.pStrmOut);
608 LogFlowFunc(("LUN#%RU8: Opened output with rc=%Rrc\n", uLUN, rc));
609 if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
610 {
611 AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
612 rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
613 pDrv->pConnector, pDrv->Out.pStrmOut,
614 0 /* uFlags */,
615 &pDrv->Out.phStrmOut);
616 }
617
618 RTStrFree(pszDesc);
619 uLUN++;
620 }
621 break;
622 }
623
624 case MC_INDEX: /* Mic in */
625 {
626 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
627 {
628 if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] ac97.mc", uLUN) <= 0)
629 {
630 rc = VERR_NO_MEMORY;
631 break;
632 }
633
634 rc = pDrv->pConnector->pfnOpenIn(pDrv->pConnector,
635 pszDesc, PDMAUDIORECSOURCE_MIC, &streamCfg, &pDrv->MicIn.pStrmIn);
636 LogFlowFunc(("LUN#%RU8: Opened mic input with rc=%Rrc\n", uLUN, rc));
637 if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
638 {
639 AudioMixerRemoveStream(pThis->pSinkMicIn, pDrv->MicIn.phStrmIn);
640 rc = AudioMixerAddStreamIn(pThis->pSinkMicIn,
641 pDrv->pConnector, pDrv->MicIn.pStrmIn,
642 0 /* uFlags */,
643 &pDrv->MicIn.phStrmIn);
644 }
645
646 RTStrFree(pszDesc);
647 uLUN++;
648 }
649 break;
650 }
651
652 default:
653 AssertMsgFailed(("Unsupported index %d\n", index));
654 rc = VERR_NOT_SUPPORTED;
655 break;
656 }
657 }
658 else
659 {
660 switch (index)
661 {
662 case PI_INDEX:
663 {
664 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
665 {
666 pDrv->pConnector->pfnCloseIn(pDrv->pConnector, pDrv->LineIn.pStrmIn);
667 AudioMixerRemoveStream(pThis->pSinkLineIn, pDrv->LineIn.phStrmIn);
668
669 pDrv->LineIn.pStrmIn = NULL;
670 pDrv->LineIn.phStrmIn = NULL;
671 }
672
673 LogFlowFunc(("Closed line input\n"));
674 break;
675 }
676
677 case PO_INDEX:
678 {
679 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
680 {
681 pDrv->pConnector->pfnCloseOut(pDrv->pConnector, pDrv->Out.pStrmOut);
682 AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
683
684 pDrv->Out.pStrmOut = NULL;
685 pDrv->Out.phStrmOut = NULL;
686 }
687
688 LogFlowFunc(("Closed output\n"));
689 break;
690 }
691
692 case MC_INDEX:
693 {
694 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
695 {
696 pDrv->pConnector->pfnCloseIn(pDrv->pConnector, pDrv->MicIn.pStrmIn);
697 AudioMixerRemoveStream(pThis->pSinkMicIn, pDrv->MicIn.phStrmIn);
698
699 pDrv->MicIn.pStrmIn = NULL;
700 pDrv->MicIn.phStrmIn = NULL;
701 }
702
703 LogFlowFunc(("Closed microphone input\n"));
704 break;
705 }
706
707 default:
708 AssertMsgFailed(("Unsupported index %d\n", index));
709 break;
710 }
711
712 rc = VINF_SUCCESS;
713 }
714
715 AudioMixerInvalidate(pThis->pMixer);
716#else
717 if (freq)
718 {
719 audsettings_t as;
720 as.freq = freq;
721 as.nchannels = 2;
722 as.fmt = AUD_FMT_S16;
723 as.endianness = 0;
724
725 switch (index)
726 {
727 case PI_INDEX: /* PCM in */
728 pThis->voice_pi = AUD_open_in(&pThis->card, pThis->voice_pi, "ac97.pi", pThis, ichac97InputCallback, &as);
729#ifdef LOG_VOICES
730 LogRel(("AC97: open PI freq=%d (%s)\n", freq, pThis->voice_pi ? "ok" : "FAIL"));
731#endif
732 rc = pThis->voice_pi ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
733 break;
734
735 case PO_INDEX: /* PCM out */
736 pThis->voice_po = AUD_open_out(&pThis->card, pThis->voice_po, "ac97.po", pThis, ichac97OutputCallback, &as);
737#ifdef LOG_VOICES
738 LogRel(("AC97: open PO freq=%d (%s)\n", freq, pThis->voice_po ? "ok" : "FAIL"));
739#endif
740 rc = pThis->voice_po ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
741 break;
742
743 case MC_INDEX: /* Mic in */
744 pThis->voice_mc = AUD_open_in(&pThis->card, pThis->voice_mc, "ac97.mc", pThis, ichac97MicInCallback, &as);
745#ifdef LOG_VOICES
746 LogRel(("AC97: open MC freq=%d (%s)\n", freq, pThis->voice_mc ? "ok" : "FAIL"));
747#endif
748 rc = pThis->voice_mc ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
749 break;
750 }
751 }
752 else
753 {
754 switch (index)
755 {
756 case PI_INDEX:
757 AUD_close_in(&pThis->card, pThis->voice_pi);
758 pThis->voice_pi = NULL;
759#ifdef LOG_VOICES
760 LogRel(("AC97: Closing PCM IN\n"));
761#endif
762 break;
763
764 case PO_INDEX:
765 AUD_close_out(&pThis->card, pThis->voice_po);
766 pThis->voice_po = NULL;
767#ifdef LOG_VOICES
768 LogRel(("AC97: Closing PCM OUT\n"));
769#endif
770 break;
771
772 case MC_INDEX:
773 AUD_close_in(&pThis->card, pThis->voice_mc);
774 pThis->voice_mc = NULL;
775#ifdef LOG_VOICES
776 LogRel(("AC97: Closing MIC IN\n"));
777#endif
778 break;
779 }
780
781 rc = VINF_SUCCESS;
782 }
783#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
784
785 LogFlowFuncLeaveRC(rc);
786}
787
788/** @todo r=andy D'oh, pretty bad argument handling -- fix this! */
789static void ichac97ResetStreams(PAC97STATE pThis, uint8_t active[LAST_INDEX])
790{
791 uint16_t uFreq = ichac97MixerLoad(pThis, AC97_PCM_LR_ADC_Rate);
792 bool fEnable = RT_BOOL(active[PI_INDEX]);
793 LogFlowFunc(("Input ADC uFreq=%RU16, fEnabled=%RTbool\n", uFreq, fEnable));
794
795 ichac97OpenStream(pThis, PI_INDEX, uFreq);
796
797#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
798 PAC97DRIVER pDrv;
799 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
800 pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, fEnable);
801#else
802 AUD_set_active_in(pThis->voice_pi, active[PI_INDEX]);
803#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
804
805 uFreq = ichac97MixerLoad(pThis, AC97_PCM_Front_DAC_Rate);
806 fEnable = RT_BOOL(active[PO_INDEX]);
807 LogFlowFunc(("Output DAC uFreq=%RU16, fEnabled=%RTbool\n", uFreq, fEnable));
808
809 ichac97OpenStream(pThis, PO_INDEX, uFreq);
810
811#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
812 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
813 pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, fEnable);
814#else
815 AUD_set_active_out(pThis->voice_po, active[PO_INDEX]);
816#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
817
818 uFreq = ichac97MixerLoad(pThis, AC97_MIC_ADC_Rate);
819 fEnable = RT_BOOL(active[MC_INDEX]);
820 LogFlowFunc(("Mic ADC uFreq=%RU16, fEnabled=%RTbool\n", uFreq, fEnable));
821
822 ichac97OpenStream(pThis, MC_INDEX, uFreq);
823
824#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
825 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
826 pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, fEnable);
827#else
828 AUD_set_active_in(pThis->voice_mc, active[MC_INDEX]);
829#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
830}
831
832#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
833static void ichac97SetVolume(PAC97STATE pThis, int index, PDMAUDIOMIXERCTL mt, uint32_t val)
834#else
835static void ichac97SetVolume(PAC97STATE pThis, int index, audmixerctl_t mt, uint32_t val)
836#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
837{
838 int mute = (val >> MUTE_SHIFT) & 1;
839 uint8_t rvol = val & VOL_MASK;
840 uint8_t lvol = (val >> 8) & VOL_MASK;
841
842 /* For the master volume, 0 corresponds to 0dB gain. But for the other
843 * volume controls, 0 corresponds to +12dB and 8 to 0dB. */
844 if (mt != PDMAUDIOMIXERCTL_VOLUME)
845 {
846 /* NB: Currently there is no gain support, only attenuation. */
847 lvol = lvol < 8 ? 0 : lvol - 8;
848 rvol = rvol < 8 ? 0 : rvol - 8;
849 }
850
851 /* AC'97 has 1.5dB steps; we use 0.375dB steps. */
852 rvol = 255 - rvol * 4;
853 lvol = 255 - lvol * 4;
854
855 LogFunc(("mt=%ld, val=%RX32, mute=%RTbool\n", mt, val, RT_BOOL(mute)));
856
857#ifdef SOFT_VOLUME
858# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
859 if (pThis->pMixer) /* Device can be in reset state, so no mixer available. */
860 {
861 PDMAUDIOVOLUME vol = { RT_BOOL(mute), lvol, rvol };
862 switch (mt)
863 {
864 case PDMAUDIOMIXERCTL_VOLUME:
865 AudioMixerSetMasterVolume(pThis->pMixer, &vol);
866 break;
867
868 case PDMAUDIOMIXERCTL_PCM:
869 AudioMixerSetSinkVolume(pThis->pSinkOutput, &vol);
870 break;
871
872 case PDMAUDIOMIXERCTL_MIC_IN:
873 AudioMixerSetSinkVolume(pThis->pSinkMicIn, &vol);
874 break;
875
876 case PDMAUDIOMIXERCTL_LINE_IN:
877 AudioMixerSetSinkVolume(pThis->pSinkLineIn, &vol);
878 break;
879
880 default:
881 break;
882 }
883 }
884# else /* !VBOX_WITH_PDM_AUDIO_DRIVER */
885 if (index == AC97_Master_Volume_Mute)
886 AUD_set_volume_out(pThis->voice_po, mute, lvol, rvol);
887 else
888 AUD_set_volume(mt, &mute, &lvol, &rvol);
889# endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
890
891#else /* !SOFT_VOLUME */
892 AUD_set_volume(mt, &mute, &lvol, &rvol);
893#endif /* SOFT_VOLUME */
894
895 rvol = VOL_MASK - ((VOL_MASK * rvol) / 255);
896 lvol = VOL_MASK - ((VOL_MASK * lvol) / 255);
897
898 /*
899 * From AC'97 SoundMax Codec AD1981A: "Because AC '97 defines 6-bit volume registers, to
900 * maintain compatibility whenever the D5 or D13 bits are set to `1,' their respective
901 * lower five volume bits are automatically set to `1' by the Codec logic. On readback,
902 * all lower 5 bits will read ones whenever these bits are set to `1.'"
903 *
904 * Linux ALSA depends on this behavior.
905 */
906 if (val & RT_BIT(5))
907 val |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
908 if (val & RT_BIT(13))
909 val |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
910
911 ichac97MixerStore(pThis, index, val);
912}
913
914static PDMAUDIORECSOURCE ichac97IndextoRecSource(uint8_t i)
915{
916 switch (i)
917 {
918 case REC_MIC: return PDMAUDIORECSOURCE_MIC;
919 case REC_CD: return PDMAUDIORECSOURCE_CD;
920 case REC_VIDEO: return PDMAUDIORECSOURCE_VIDEO;
921 case REC_AUX: return PDMAUDIORECSOURCE_AUX;
922 case REC_LINE_IN: return PDMAUDIORECSOURCE_LINE_IN;
923 case REC_PHONE: return PDMAUDIORECSOURCE_PHONE;
924 default:
925 break;
926 }
927
928 LogFlowFunc(("Unknown record source %d, using MIC\n", i));
929 return PDMAUDIORECSOURCE_MIC;
930}
931
932static uint8_t ichac97RecSourceToIndex(PDMAUDIORECSOURCE rs)
933{
934 switch (rs)
935 {
936 case PDMAUDIORECSOURCE_MIC: return REC_MIC;
937 case PDMAUDIORECSOURCE_CD: return REC_CD;
938 case PDMAUDIORECSOURCE_VIDEO: return REC_VIDEO;
939 case PDMAUDIORECSOURCE_AUX: return REC_AUX;
940 case PDMAUDIORECSOURCE_LINE_IN: return REC_LINE_IN;
941 case PDMAUDIORECSOURCE_PHONE: return REC_PHONE;
942 default:
943 break;
944 }
945
946 LogFlowFunc(("Unknown audio recording source %d using MIC\n", rs));
947 return REC_MIC;
948}
949
950static void ichac97RecordSelect(PAC97STATE pThis, uint32_t val)
951{
952 uint8_t rs = val & REC_MASK;
953 uint8_t ls = (val >> 8) & REC_MASK;
954 PDMAUDIORECSOURCE ars = ichac97IndextoRecSource(rs);
955 PDMAUDIORECSOURCE als = ichac97IndextoRecSource(ls);
956 //AUD_set_record_source(&als, &ars);
957 rs = ichac97RecSourceToIndex(ars);
958 ls = ichac97RecSourceToIndex(als);
959 ichac97MixerStore(pThis, AC97_Record_Select, rs | (ls << 8));
960}
961
962static void ichac97MixerReset(PAC97STATE pThis)
963{
964 LogFlowFuncEnter();
965
966 RT_ZERO(pThis->mixer_data);
967
968#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
969 PAC97DRIVER pDrv;
970
971 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
972 {
973 pDrv->Out.phStrmOut = NULL;
974 pDrv->LineIn.phStrmIn = NULL;
975 pDrv->MicIn.phStrmIn = NULL;
976 }
977
978 pThis->pSinkOutput = NULL;
979 pThis->pSinkLineIn = NULL;
980 pThis->pSinkMicIn = NULL;
981
982 if (pThis->pMixer)
983 {
984 AudioMixerDestroy(pThis->pMixer);
985 pThis->pMixer = NULL;
986 }
987
988 int rc2 = AudioMixerCreate("AC'97 Mixer", 0 /* uFlags */, &pThis->pMixer);
989 if (RT_SUCCESS(rc2))
990 {
991 /* Set a default audio format for our mixer. */
992 PDMAUDIOSTREAMCFG streamCfg;
993 streamCfg.uHz = 41000;
994 streamCfg.cChannels = 2;
995 streamCfg.enmFormat = AUD_FMT_S16;
996 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
997
998 rc2 = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
999 AssertRC(rc2);
1000
1001 /* Add all required audio sinks. */
1002 rc2 = AudioMixerAddSink(pThis->pMixer, "[Playback] PCM Output",
1003 AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
1004 AssertRC(rc2);
1005
1006 rc2 = AudioMixerAddSink(pThis->pMixer, "[Recording] Line In",
1007 AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
1008 AssertRC(rc2);
1009
1010 rc2 = AudioMixerAddSink(pThis->pMixer, "[Recording] Microphone In",
1011 AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn);
1012 AssertRC(rc2);
1013 }
1014#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1015
1016 ichac97MixerStore(pThis, AC97_Reset , 0x0000); /* 6940 */
1017 ichac97MixerStore(pThis, AC97_Master_Volume_Mono_Mute , 0x8000);
1018 ichac97MixerStore(pThis, AC97_PC_BEEP_Volume_Mute , 0x0000);
1019
1020 ichac97MixerStore(pThis, AC97_Phone_Volume_Mute , 0x8008);
1021 ichac97MixerStore(pThis, AC97_Mic_Volume_Mute , 0x8008);
1022 ichac97MixerStore(pThis, AC97_CD_Volume_Mute , 0x8808);
1023 ichac97MixerStore(pThis, AC97_Aux_Volume_Mute , 0x8808);
1024 ichac97MixerStore(pThis, AC97_Record_Gain_Mic_Mute , 0x8000);
1025 ichac97MixerStore(pThis, AC97_General_Purpose , 0x0000);
1026 ichac97MixerStore(pThis, AC97_3D_Control , 0x0000);
1027 ichac97MixerStore(pThis, AC97_Powerdown_Ctrl_Stat , 0x000f);
1028
1029 ichac97MixerStore(pThis, AC97_Extended_Audio_ID , 0x0809);
1030 ichac97MixerStore(pThis, AC97_Extended_Audio_Ctrl_Stat, 0x0009);
1031 ichac97MixerStore(pThis, AC97_PCM_Front_DAC_Rate , 0xbb80);
1032 ichac97MixerStore(pThis, AC97_PCM_Surround_DAC_Rate , 0xbb80);
1033 ichac97MixerStore(pThis, AC97_PCM_LFE_DAC_Rate , 0xbb80);
1034 ichac97MixerStore(pThis, AC97_PCM_LR_ADC_Rate , 0xbb80);
1035 ichac97MixerStore(pThis, AC97_MIC_ADC_Rate , 0xbb80);
1036
1037 if (PCIDevGetSubSystemVendorId(&pThis->PciDev) == 0x1028)
1038 {
1039 /* Analog Devices 1980 (AD1980) */
1040 ichac97MixerStore(pThis, AC97_Vendor_ID1 , 0x4144);
1041 ichac97MixerStore(pThis, AC97_Vendor_ID2 , 0x5370);
1042 }
1043 else
1044 {
1045 /* Sigmatel 9700 (STAC9700) */
1046 ichac97MixerStore(pThis, AC97_Vendor_ID1 , 0x8384);
1047 ichac97MixerStore(pThis, AC97_Vendor_ID2 , 0x7600); /* 7608 */
1048 }
1049 ichac97RecordSelect(pThis, 0);
1050# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1051 ichac97SetVolume(pThis, AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME, 0x8000);
1052 ichac97SetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_PCM, 0x8808);
1053 ichac97SetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808);
1054# else
1055 ichac97SetVolume(pThis, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME, 0x8000);
1056 ichac97SetVolume(pThis, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM, 0x8808);
1057 ichac97SetVolume(pThis, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808);
1058# endif
1059
1060 /* Reset all streams. */
1061 uint8_t active[LAST_INDEX] = { 0 };
1062 ichac97ResetStreams(pThis, active);
1063}
1064
1065/**
1066 * Writes data from the device to the host backends.
1067 *
1068 * @return IPRT status code.
1069 * @return int
1070 * @param pThis
1071 * @param pReg
1072 * @param cbMax
1073 * @param pcbWritten
1074 */
1075static int ichac97WriteAudio(PAC97STATE pThis, PAC97BMREG pReg, uint32_t cbMax, uint32_t *pcbWritten)
1076{
1077 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1078 AssertPtrReturn(pReg, VERR_INVALID_POINTER);
1079 AssertReturn(cbMax, VERR_INVALID_PARAMETER);
1080 AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
1081
1082 PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
1083
1084 uint32_t addr = pReg->bd.addr;
1085 uint32_t cbWrittenTotal = 0;
1086 uint32_t cbToRead;
1087
1088 uint32_t cbToWrite = RT_MIN((uint32_t)(pReg->picb << 1), cbMax);
1089 if (!cbToWrite)
1090 {
1091 *pcbWritten = 0;
1092 return VINF_EOF;
1093 }
1094
1095 int rc = VINF_SUCCESS;
1096
1097 LogFlowFunc(("pReg=%p, cbMax=%RU32, cbToWrite=%RU32\n", pReg, cbMax, cbToWrite));
1098
1099 while (cbToWrite)
1100 {
1101 uint32_t cbWrittenMin = UINT32_MAX;
1102
1103 cbToRead = RT_MIN(cbToWrite, pThis->cbReadWriteBuf);
1104 PDMDevHlpPhysRead(pDevIns, addr, pThis->pvReadWriteBuf, cbToRead); /** @todo Check rc? */
1105
1106#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1107 uint32_t cbWritten;
1108
1109 /* Just multiplex the output to the connected backends.
1110 * No need to utilize the virtual mixer here (yet). */
1111 PAC97DRIVER pDrv;
1112 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
1113 {
1114 int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
1115 pThis->pvReadWriteBuf, cbToRead, &cbWritten);
1116 AssertRCBreak(rc);
1117 if (RT_FAILURE(rc2))
1118 continue;
1119
1120 cbWrittenMin = RT_MIN(cbWrittenMin, cbWritten);
1121 LogFlowFunc(("\tLUN#%RU8: cbWritten=%RU32, cWrittenMin=%RU32\n", pDrv->uLUN, cbWritten, cbWrittenMin));
1122 }
1123#else
1124 cbWrittenMin = AUD_write(pThis->voice_po, pThis->pvReadWriteBuf, cbToRead);
1125#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1126 LogFlowFunc(("\tcbToRead=%RU32, cbWrittenMin=%RU32, cbToWrite=%RU32, cbLeft=%RU32\n",
1127 cbToRead, cbWrittenMin, cbToWrite, cbToWrite - cbWrittenMin));
1128
1129 if (!cbWrittenMin)
1130 {
1131 rc = VINF_EOF;
1132 break;
1133 }
1134
1135 Assert(cbWrittenMin != UINT32_MAX);
1136 Assert(cbToWrite >= cbWrittenMin);
1137 cbToWrite -= cbWrittenMin;
1138 addr += cbWrittenMin;
1139 cbWrittenTotal += cbWrittenMin;
1140 }
1141
1142 pReg->bd.addr = addr;
1143
1144 if (RT_SUCCESS(rc))
1145 {
1146 if (!cbToWrite) /* All data written? */
1147 {
1148 if (cbToRead < 4)
1149 {
1150 AssertMsgFailed(("Unable to save last written sample, cbToRead < 4 (is %RU32)\n", cbToRead));
1151 pThis->last_samp = 0;
1152 }
1153 else
1154 pThis->last_samp = *(uint32_t *)&pThis->pvReadWriteBuf[cbToRead - 4];
1155 }
1156
1157 *pcbWritten = cbWrittenTotal;
1158 }
1159
1160 LogFlowFunc(("cbWrittenTotal=%RU32, rc=%Rrc\n", cbWrittenTotal, rc));
1161 return rc;
1162}
1163
1164static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
1165{
1166 if (!(pThis->bup_flag & BUP_SET))
1167 {
1168 if (pThis->bup_flag & BUP_LAST)
1169 {
1170 unsigned int i;
1171 uint32_t *p = (uint32_t*)pThis->silence;
1172 for (i = 0; i < sizeof(pThis->silence) / 4; i++)
1173 *p++ = pThis->last_samp;
1174 }
1175 else
1176 RT_ZERO(pThis->silence);
1177
1178 pThis->bup_flag |= BUP_SET;
1179 }
1180
1181 while (cbElapsed)
1182 {
1183 uint32_t cbWrittenMin = UINT32_MAX;
1184
1185 uint32_t cbToWrite = RT_MIN(cbElapsed, (uint32_t)sizeof(pThis->silence));
1186 while (cbToWrite)
1187 {
1188#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1189 PAC97DRIVER pDrv;
1190 uint32_t cbWritten;
1191 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
1192 {
1193 int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
1194 pThis->silence, cbToWrite, &cbWritten);
1195 if (RT_FAILURE(rc2))
1196 continue;
1197
1198 cbWrittenMin = RT_MIN(cbWrittenMin, cbWritten);
1199 }
1200#else
1201 cbWrittenMin = AUD_write(pThis->voice_po, pThis->silence, cbToWrite);
1202#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1203
1204 if (!cbWrittenMin)
1205 return;
1206
1207 Assert(cbToWrite >= cbWrittenMin);
1208 cbToWrite -= cbWrittenMin;
1209 Assert(cbElapsed >= cbWrittenMin);
1210 cbElapsed -= cbWrittenMin;
1211 }
1212 }
1213}
1214
1215static int ichac97ReadAudio(PAC97STATE pThis, PAC97BMREG pReg, uint32_t cbMax, uint32_t *pcbRead)
1216{
1217 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1218 AssertPtrReturn(pReg, VERR_INVALID_POINTER);
1219 AssertReturn(cbMax, VERR_INVALID_PARAMETER);
1220 AssertPtrReturn(pcbRead, VERR_INVALID_POINTER);
1221
1222 PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
1223
1224 int rc;
1225
1226#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1227 /* Select audio sink to process. */
1228 PAUDMIXSINK pSink = (pReg - pThis->bm_regs) == MC_INDEX ? pThis->pSinkMicIn : pThis->pSinkLineIn;
1229 AssertPtr(pSink);
1230
1231 uint32_t cbRead = 0;
1232
1233 uint32_t cbMixBuf = cbMax;
1234 uint32_t cbToRead = RT_MIN((uint32_t)(pReg->picb << 1), cbMixBuf);
1235
1236 if (!cbToRead)
1237 {
1238 *pcbRead = 0;
1239 return VINF_EOF;
1240 }
1241
1242 uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbMixBuf);
1243 if (pvMixBuf)
1244 {
1245 rc = AudioMixerProcessSinkIn(pSink, AUDMIXOP_BLEND, pvMixBuf, cbToRead, &cbRead);
1246 if ( RT_SUCCESS(rc)
1247 && cbRead)
1248 {
1249 PDMDevHlpPCIPhysWrite(pDevIns, pReg->bd.addr, pvMixBuf, cbRead);
1250 pReg->bd.addr += cbRead;
1251 }
1252
1253 RTMemFree(pvMixBuf);
1254 }
1255 else
1256 rc = VERR_NO_MEMORY;
1257
1258 if (RT_SUCCESS(rc))
1259 {
1260 Assert(cbRead);
1261 *pcbRead = cbRead;
1262 }
1263
1264 return rc;
1265#else
1266 rc = VINF_SUCCESS;
1267
1268 uint32_t addr = pReg->bd.addr;
1269 uint32_t temp = pReg->picb << 1;
1270 uint32_t nread = 0;
1271 int to_copy = 0;
1272
1273 SWVoiceIn *voice = (pReg - pThis->bm_regs) == MC_INDEX ? pThis->voice_mc : pThis->voice_pi;
1274
1275 temp = audio_MIN(temp, (uint32_t)cbMax);
1276 if (!temp)
1277 {
1278 *pcbRead = 0;
1279 return VINF_EOF;
1280 }
1281
1282 uint8_t tmpbuf[4096];
1283 while (temp)
1284 {
1285 int acquired;
1286 to_copy = audio_MIN(temp, sizeof(tmpbuf));
1287 acquired = AUD_read(voice, tmpbuf, to_copy);
1288 if (!acquired)
1289 {
1290 rc = VERR_GENERAL_FAILURE; /* Not worth fixing anymore. */
1291 break;
1292 }
1293 PDMDevHlpPCIPhysWrite(pDevIns, addr, tmpbuf, acquired);
1294 temp -= acquired;
1295 addr += acquired;
1296 nread += acquired;
1297 }
1298
1299 pReg->bd.addr = addr;
1300
1301 if (RT_SUCCESS(rc))
1302 *pcbRead = nread;
1303
1304 return rc;
1305#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1306}
1307
1308#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1309static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1310{
1311 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
1312 AssertPtrReturnVoid(pThis);
1313
1314 STAM_PROFILE_START(&pThis->StatTimer, a);
1315
1316 int rc = VINF_SUCCESS;
1317
1318 uint32_t cbInMax = 0;
1319 uint32_t cbOutMin = UINT32_MAX;
1320
1321 PAC97DRIVER pDrv;
1322
1323 uint32_t cbIn, cbOut, cSamplesLive;
1324 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
1325 {
1326 rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
1327 &cbIn, &cbOut, &cSamplesLive);
1328 if (RT_SUCCESS(rc))
1329 {
1330#ifdef DEBUG_TIMER
1331 LogFlowFunc(("\tLUN#%RU8: [1] cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, cbIn, cbOut));
1332#endif
1333 if (cSamplesLive)
1334 {
1335 uint32_t cSamplesPlayed;
1336 int rc2 = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, &cSamplesPlayed);
1337#ifdef DEBUG_TIMER
1338 if (RT_SUCCESS(rc2))
1339 LogFlowFunc(("LUN#%RU8: cSamplesLive=%RU32, cSamplesPlayed=%RU32\n",
1340 pDrv->uLUN, cSamplesLive, cSamplesPlayed));
1341#endif
1342 if (cSamplesPlayed)
1343 {
1344 rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
1345 &cbIn, &cbOut, &cSamplesLive);
1346#ifdef DEBUG_TIMER
1347 if (RT_SUCCESS(rc))
1348 LogFlowFunc(("\tLUN#%RU8: [2] cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, cbIn, cbOut));
1349#endif
1350 }
1351 }
1352
1353 cbInMax = RT_MAX(cbInMax, cbIn);
1354 cbOutMin = RT_MIN(cbOutMin, cbOut);
1355 }
1356 }
1357
1358#ifdef DEBUG_TIMER
1359 LogFlowFunc(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
1360#endif
1361
1362 if (cbOutMin == UINT32_MAX)
1363 cbOutMin = 0;
1364
1365 /*
1366 * Playback.
1367 */
1368 if (cbOutMin)
1369 {
1370 Assert(cbOutMin != UINT32_MAX);
1371 ichac97TransferAudio(pThis, PO_INDEX, cbOutMin); /** @todo Add rc! */
1372 }
1373
1374 /*
1375 * Recording.
1376 */
1377 if (cbInMax)
1378 ichac97TransferAudio(pThis, PI_INDEX, cbInMax); /** @todo Add rc! */
1379
1380 TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->uTicks);
1381
1382 STAM_PROFILE_STOP(&pThis->StatTimer, a);
1383}
1384#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1385
1386static int ichac97TransferAudio(PAC97STATE pThis, int index, uint32_t cbElapsed)
1387{
1388 LogFlowFunc(("pThis=%p, index=%d, cbElapsed=%RU32\n", pThis, index, cbElapsed));
1389
1390 PAC97BMREG pReg = &pThis->bm_regs[index];
1391 if (pReg->sr & SR_DCH) /* Controller halted? */
1392 {
1393 if (pReg->cr & CR_RPBM)
1394 {
1395 switch (index)
1396 {
1397 case PO_INDEX:
1398 ichac97WriteBUP(pThis, cbElapsed);
1399 break;
1400
1401 default:
1402 break;
1403 }
1404 }
1405
1406 return VINF_SUCCESS;
1407 }
1408
1409 int rc = VINF_SUCCESS;
1410 uint32_t cbWrittenTotal = 0;
1411
1412 while (cbElapsed >> 1)
1413 {
1414 if (!pReg->bd_valid)
1415 {
1416 LogFlowFunc(("Invalid buffer descriptor, fetching next one ...\n"));
1417 ichac97FetchBufDesc(pThis, pReg);
1418 }
1419
1420 if (!pReg->picb) /* Got a new buffer descriptor, that is, the position is 0? */
1421 {
1422 LogFlowFunc(("Fresh buffer descriptor %RU8 is empty, addr=%#x, len=%#x, skipping\n",
1423 pReg->civ, pReg->bd.addr, pReg->bd.ctl_len));
1424 if (pReg->civ == pReg->lvi)
1425 {
1426 pReg->sr |= SR_DCH; /* CELV? */
1427 pThis->bup_flag = 0;
1428
1429 rc = VINF_EOF;
1430 break;
1431 }
1432
1433 pReg->sr &= ~SR_CELV;
1434 pReg->civ = pReg->piv;
1435 pReg->piv = (pReg->piv + 1) % 32;
1436
1437 ichac97FetchBufDesc(pThis, pReg);
1438 continue;
1439 }
1440
1441 uint32_t cbTransferred;
1442 switch (index)
1443 {
1444 case PO_INDEX:
1445 {
1446 rc = ichac97WriteAudio(pThis, pReg, cbElapsed, &cbTransferred);
1447 if ( RT_SUCCESS(rc)
1448 && cbTransferred)
1449 {
1450 cbWrittenTotal += cbTransferred;
1451 Assert(cbElapsed >= cbTransferred);
1452 cbElapsed -= cbTransferred;
1453 Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
1454 pReg->picb -= (cbTransferred >> 1);
1455 }
1456 break;
1457 }
1458
1459 case PI_INDEX:
1460 case MC_INDEX:
1461 {
1462 rc = ichac97ReadAudio(pThis, pReg, cbElapsed, &cbTransferred);
1463 if ( RT_SUCCESS(rc)
1464 && cbTransferred)
1465 {
1466 Assert(cbElapsed >= cbTransferred);
1467 cbElapsed -= cbTransferred;
1468 Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
1469 pReg->picb -= (cbTransferred >> 1);
1470 }
1471 break;
1472 }
1473
1474 default:
1475 AssertMsgFailed(("Index %ld not supported\n", index));
1476 rc = VERR_NOT_SUPPORTED;
1477 break;
1478 }
1479
1480 LogFlowFunc(("pReg->picb=%#x, cbWrittenTotal=%RU32\n", pReg->picb, cbWrittenTotal));
1481
1482 if (!pReg->picb)
1483 {
1484 uint32_t new_sr = pReg->sr & ~SR_CELV;
1485
1486 if (pReg->bd.ctl_len & BD_IOC)
1487 {
1488 new_sr |= SR_BCIS;
1489 }
1490
1491 if (pReg->civ == pReg->lvi)
1492 {
1493 LogFlowFunc(("Underrun civ (%RU8) == lvi (%RU8)\n", pReg->civ, pReg->lvi));
1494 new_sr |= SR_LVBCI | SR_DCH | SR_CELV;
1495 pThis->bup_flag = (pReg->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
1496
1497 rc = VINF_EOF;
1498 }
1499 else
1500 {
1501 pReg->civ = pReg->piv;
1502 pReg->piv = (pReg->piv + 1) % 32;
1503 ichac97FetchBufDesc(pThis, pReg);
1504 }
1505
1506 ichac97UpdateStatus(pThis, pReg, new_sr);
1507 }
1508
1509 if ( RT_FAILURE(rc)
1510 || rc == VINF_EOF) /* All data processed? */
1511 {
1512 break;
1513 }
1514 }
1515
1516 LogFlowFuncLeaveRC(rc);
1517 return rc;
1518}
1519
1520#ifndef VBOX_WITH_PDM_AUDIO_DRIVER
1521static void ichac97InputCallback(void *pvContext, int cbAvail)
1522{
1523 ichac97TransferAudio((AC97STATE *)pvContext, PI_INDEX, cbAvail);
1524}
1525
1526static void ichac97MicInCallback(void *pvContext, int cbAvail)
1527{
1528 ichac97TransferAudio((AC97STATE *)pvContext, MC_INDEX, cbAvail);
1529}
1530
1531static void ichac97OutputCallback(void *pvContext, int cbFree)
1532{
1533 ichac97TransferAudio((AC97STATE *)pvContext, PO_INDEX, cbFree);
1534}
1535#endif
1536
1537/**
1538 * @callback_method_impl{FNIOMIOPORTIN}
1539 */
1540static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1541{
1542 PAC97STATE pThis = (PAC97STATE)pvUser;
1543
1544 switch (cb)
1545 {
1546 case 1:
1547 {
1548 PAC97BMREG pReg = NULL;
1549 uint32_t index = Port - pThis->IOPortBase[1];
1550 *pu32 = ~0U;
1551
1552 switch (index)
1553 {
1554 case CAS:
1555 /* Codec Access Semaphore Register */
1556 LogFlowFunc(("CAS %d\n", pThis->cas));
1557 *pu32 = pThis->cas;
1558 pThis->cas = 1;
1559 break;
1560 case PI_CIV:
1561 case PO_CIV:
1562 case MC_CIV:
1563 /* Current Index Value Register */
1564 pReg = &pThis->bm_regs[GET_BM(index)];
1565 *pu32 = pReg->civ;
1566 LogFlowFunc(("CIV[%d] -> %#x\n", GET_BM(index), *pu32));
1567 break;
1568 case PI_LVI:
1569 case PO_LVI:
1570 case MC_LVI:
1571 /* Last Valid Index Register */
1572 pReg = &pThis->bm_regs[GET_BM(index)];
1573 *pu32 = pReg->lvi;
1574 LogFlowFunc(("LVI[%d] -> %#x\n", GET_BM(index), *pu32));
1575 break;
1576 case PI_PIV:
1577 case PO_PIV:
1578 case MC_PIV:
1579 /* Prefetched Index Value Register */
1580 pReg = &pThis->bm_regs[GET_BM(index)];
1581 *pu32 = pReg->piv;
1582 LogFlowFunc(("PIV[%d] -> %#x\n", GET_BM(index), *pu32));
1583 break;
1584 case PI_CR:
1585 case PO_CR:
1586 case MC_CR:
1587 /* Control Register */
1588 pReg = &pThis->bm_regs[GET_BM(index)];
1589 *pu32 = pReg->cr;
1590 LogFlowFunc(("CR[%d] -> %#x\n", GET_BM(index), *pu32));
1591 break;
1592 case PI_SR:
1593 case PO_SR:
1594 case MC_SR:
1595 /* Status Register (lower part) */
1596 pReg = &pThis->bm_regs[GET_BM(index)];
1597 *pu32 = pReg->sr & 0xff;
1598 LogFlowFunc(("SRb[%d] -> %#x\n", GET_BM(index), *pu32));
1599 break;
1600 default:
1601 LogFlowFunc(("U nabm readb %#x -> %#x\n", Port, *pu32));
1602 break;
1603 }
1604 break;
1605 }
1606
1607 case 2:
1608 {
1609 PAC97BMREG pReg = NULL;
1610 uint32_t index = Port - pThis->IOPortBase[1];
1611 *pu32 = ~0U;
1612
1613 switch (index)
1614 {
1615 case PI_SR:
1616 case PO_SR:
1617 case MC_SR:
1618 /* Status Register */
1619 pReg = &pThis->bm_regs[GET_BM(index)];
1620 *pu32 = pReg->sr;
1621 LogFlowFunc(("SR[%d] -> %#x\n", GET_BM(index), *pu32));
1622 break;
1623 case PI_PICB:
1624 case PO_PICB:
1625 case MC_PICB:
1626 /* Position in Current Buffer Register */
1627 pReg = &pThis->bm_regs[GET_BM(index)];
1628 *pu32 = pReg->picb;
1629 LogFlowFunc(("PICB[%d] -> %#x\n", GET_BM(index), *pu32));
1630 break;
1631 default:
1632 LogFlowFunc(("U nabm readw %#x -> %#x\n", Port, *pu32));
1633 break;
1634 }
1635 break;
1636 }
1637
1638 case 4:
1639 {
1640 PAC97BMREG pReg = NULL;
1641 uint32_t index = Port - pThis->IOPortBase[1];
1642 *pu32 = ~0U;
1643
1644 switch (index)
1645 {
1646 case PI_BDBAR:
1647 case PO_BDBAR:
1648 case MC_BDBAR:
1649 /* Buffer Descriptor Base Address Register */
1650 pReg = &pThis->bm_regs[GET_BM(index)];
1651 *pu32 = pReg->bdbar;
1652 LogFlowFunc(("BMADDR[%d] -> %#x\n", GET_BM(index), *pu32));
1653 break;
1654 case PI_CIV:
1655 case PO_CIV:
1656 case MC_CIV:
1657 /* 32-bit access: Current Index Value Register +
1658 * Last Valid Index Register +
1659 * Status Register */
1660 pReg = &pThis->bm_regs[GET_BM(index)];
1661 *pu32 = pReg->civ | (pReg->lvi << 8) | (pReg->sr << 16);
1662 LogFlowFunc(("CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM(index), pReg->civ, pReg->lvi, pReg->sr));
1663 break;
1664 case PI_PICB:
1665 case PO_PICB:
1666 case MC_PICB:
1667 /* 32-bit access: Position in Current Buffer Register +
1668 * Prefetched Index Value Register +
1669 * Control Register */
1670 pReg = &pThis->bm_regs[GET_BM(index)];
1671 *pu32 = pReg->picb | (pReg->piv << 16) | (pReg->cr << 24);
1672 LogFlowFunc(("PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM(index), *pu32, pReg->picb, pReg->piv, pReg->cr));
1673 break;
1674 case GLOB_CNT:
1675 /* Global Control */
1676 *pu32 = pThis->glob_cnt;
1677 LogFlowFunc(("glob_cnt -> %#x\n", *pu32));
1678 break;
1679 case GLOB_STA:
1680 /* Global Status */
1681 *pu32 = pThis->glob_sta | GS_S0CR;
1682 LogFlowFunc(("glob_sta -> %#x\n", *pu32));
1683 break;
1684 default:
1685 LogFlowFunc(("U nabm readl %#x -> %#x\n", Port, *pu32));
1686 break;
1687 }
1688 break;
1689 }
1690
1691 default:
1692 return VERR_IOM_IOPORT_UNUSED;
1693 }
1694 return VINF_SUCCESS;
1695}
1696
1697/**
1698 * @callback_method_impl{FNIOMIOPORTOUT}
1699 */
1700static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1701{
1702 PAC97STATE pThis = (PAC97STATE)pvUser;
1703
1704 switch (cb)
1705 {
1706 case 1:
1707 {
1708 PAC97BMREG pReg = NULL;
1709 uint32_t index = Port - pThis->IOPortBase[1];
1710 switch (index)
1711 {
1712 case PI_LVI:
1713 case PO_LVI:
1714 case MC_LVI:
1715 /* Last Valid Index */
1716 pReg = &pThis->bm_regs[GET_BM(index)];
1717 if ((pReg->cr & CR_RPBM) && (pReg->sr & SR_DCH))
1718 {
1719 pReg->sr &= ~(SR_DCH | SR_CELV);
1720 pReg->civ = pReg->piv;
1721 pReg->piv = (pReg->piv + 1) % 32;
1722 ichac97FetchBufDesc(pThis, pReg);
1723 }
1724 pReg->lvi = u32 % 32;
1725 LogFlowFunc(("LVI[%d] <- %#x\n", GET_BM(index), u32));
1726 break;
1727 case PI_CR:
1728 case PO_CR:
1729 case MC_CR:
1730 /* Control Register */
1731 pReg = &pThis->bm_regs[GET_BM(index)];
1732 if (u32 & CR_RR)
1733 ichac97ResetBMRegs(pThis, pReg);
1734 else
1735 {
1736 pReg->cr = u32 & CR_VALID_MASK;
1737 if (!(pReg->cr & CR_RPBM))
1738 {
1739 ichac97StreamSetActive(pThis, pReg - pThis->bm_regs, 0);
1740 pReg->sr |= SR_DCH;
1741 }
1742 else
1743 {
1744 pReg->civ = pReg->piv;
1745 pReg->piv = (pReg->piv + 1) % 32;
1746 ichac97FetchBufDesc(pThis, pReg);
1747 pReg->sr &= ~SR_DCH;
1748 ichac97StreamSetActive(pThis, pReg - pThis->bm_regs, 1);
1749 }
1750 }
1751 LogFlowFunc(("CR[%d] <- %#x (cr %#x)\n", GET_BM(index), u32, pReg->cr));
1752 break;
1753 case PI_SR:
1754 case PO_SR:
1755 case MC_SR:
1756 /* Status Register */
1757 pReg = &pThis->bm_regs[GET_BM(index)];
1758 pReg->sr |= u32 & ~(SR_RO_MASK | SR_WCLEAR_MASK);
1759 ichac97UpdateStatus(pThis, pReg, pReg->sr & ~(u32 & SR_WCLEAR_MASK));
1760 LogFlowFunc(("SR[%d] <- %#x (sr %#x)\n", GET_BM(index), u32, pReg->sr));
1761 break;
1762 default:
1763 LogFlowFunc(("U nabm writeb %#x <- %#x\n", Port, u32));
1764 break;
1765 }
1766 break;
1767 }
1768
1769 case 2:
1770 {
1771 PAC97BMREG pReg = NULL;
1772 uint32_t index = Port - pThis->IOPortBase[1];
1773 switch (index)
1774 {
1775 case PI_SR:
1776 case PO_SR:
1777 case MC_SR:
1778 /* Status Register */
1779 pReg = &pThis->bm_regs[GET_BM(index)];
1780 pReg->sr |= u32 & ~(SR_RO_MASK | SR_WCLEAR_MASK);
1781 ichac97UpdateStatus(pThis, pReg, pReg->sr & ~(u32 & SR_WCLEAR_MASK));
1782 LogFlowFunc(("SR[%d] <- %#x (sr %#x)\n", GET_BM(index), u32, pReg->sr));
1783 break;
1784 default:
1785 LogFlowFunc(("U nabm writew %#x <- %#x\n", Port, u32));
1786 break;
1787 }
1788 break;
1789 }
1790
1791 case 4:
1792 {
1793 PAC97BMREG pReg = NULL;
1794 uint32_t index = Port - pThis->IOPortBase[1];
1795 switch (index)
1796 {
1797 case PI_BDBAR:
1798 case PO_BDBAR:
1799 case MC_BDBAR:
1800 /* Buffer Descriptor list Base Address Register */
1801 pReg = &pThis->bm_regs[GET_BM(index)];
1802 pReg->bdbar = u32 & ~3;
1803 LogFlowFunc(("BDBAR[%d] <- %#x (bdbar %#x)\n", GET_BM(index), u32, pReg->bdbar));
1804 break;
1805 case GLOB_CNT:
1806 /* Global Control */
1807 if (u32 & GC_WR)
1808 ichac97WarmReset(pThis);
1809 if (u32 & GC_CR)
1810 ichac97ColdReset(pThis);
1811 if (!(u32 & (GC_WR | GC_CR)))
1812 pThis->glob_cnt = u32 & GC_VALID_MASK;
1813 LogFlowFunc(("glob_cnt <- %#x (glob_cnt %#x)\n", u32, pThis->glob_cnt));
1814 break;
1815 case GLOB_STA:
1816 /* Global Status */
1817 pThis->glob_sta &= ~(u32 & GS_WCLEAR_MASK);
1818 pThis->glob_sta |= (u32 & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK;
1819 LogFlowFunc(("glob_sta <- %#x (glob_sta %#x)\n", u32, pThis->glob_sta));
1820 break;
1821 default:
1822 LogFlowFunc(("U nabm writel %#x <- %#x\n", Port, u32));
1823 break;
1824 }
1825 break;
1826 }
1827
1828 default:
1829 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1830 break;
1831 }
1832 return VINF_SUCCESS;
1833}
1834
1835/**
1836 * @callback_method_impl{FNIOMIOPORTIN}
1837 */
1838static DECLCALLBACK(int) ichac97IOPortNAMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1839{
1840 PAC97STATE pThis = (PAC97STATE)pvUser;
1841
1842 switch (cb)
1843 {
1844 case 1:
1845 {
1846 LogFlowFunc(("U nam readb %#x\n", Port));
1847 pThis->cas = 0;
1848 *pu32 = ~0U;
1849 break;
1850 }
1851
1852 case 2:
1853 {
1854 uint32_t index = Port - pThis->IOPortBase[0];
1855 *pu32 = ~0U;
1856 pThis->cas = 0;
1857 switch (index)
1858 {
1859 default:
1860 *pu32 = ichac97MixerLoad(pThis, index);
1861 LogFlowFunc(("nam readw %#x -> %#x\n", Port, *pu32));
1862 break;
1863 }
1864 break;
1865 }
1866
1867 case 4:
1868 {
1869 LogFlowFunc(("U nam readl %#x\n", Port));
1870 pThis->cas = 0;
1871 *pu32 = ~0U;
1872 break;
1873 }
1874
1875 default:
1876 return VERR_IOM_IOPORT_UNUSED;
1877 }
1878 return VINF_SUCCESS;
1879}
1880
1881/**
1882 * @callback_method_impl{FNIOMIOPORTOUT}
1883 */
1884static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns,
1885 void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1886{
1887 PAC97STATE pThis = (PAC97STATE)pvUser;
1888
1889 switch (cb)
1890 {
1891 case 1:
1892 {
1893 LogFlowFunc(("U nam writeb %#x <- %#x\n", Port, u32));
1894 pThis->cas = 0;
1895 break;
1896 }
1897
1898 case 2:
1899 {
1900 uint32_t index = Port - pThis->IOPortBase[0];
1901 pThis->cas = 0;
1902 switch (index)
1903 {
1904 case AC97_Reset:
1905 ichac97MixerReset(pThis);
1906 break;
1907 case AC97_Powerdown_Ctrl_Stat:
1908 u32 &= ~0xf;
1909 u32 |= ichac97MixerLoad(pThis, index) & 0xf;
1910 ichac97MixerStore(pThis, index, u32);
1911 break;
1912 case AC97_Master_Volume_Mute:
1913#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1914 ichac97SetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME, u32);
1915#else
1916 ichac97SetVolume(pThis, index, AUD_MIXER_VOLUME, u32);
1917#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1918 break;
1919 case AC97_PCM_Out_Volume_Mute:
1920#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1921 ichac97SetVolume(pThis, index, PDMAUDIOMIXERCTL_PCM, u32);
1922#else
1923 ichac97SetVolume(pThis, index, AUD_MIXER_PCM, u32);
1924#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1925 break;
1926 case AC97_Line_In_Volume_Mute:
1927#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1928 ichac97SetVolume(pThis, index, PDMAUDIOMIXERCTL_LINE_IN, u32);
1929#else
1930 ichac97SetVolume(pThis, index, AUD_MIXER_LINE_IN, u32);
1931#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1932 break;
1933 case AC97_Record_Select:
1934 ichac97RecordSelect(pThis, u32);
1935 break;
1936 case AC97_Vendor_ID1:
1937 case AC97_Vendor_ID2:
1938 LogFlowFunc(("Attempt to write vendor ID to %#x\n", u32));
1939 break;
1940 case AC97_Extended_Audio_ID:
1941 LogFlowFunc(("Attempt to write extended audio ID to %#x\n", u32));
1942 break;
1943 case AC97_Extended_Audio_Ctrl_Stat:
1944 if (!(u32 & EACS_VRA))
1945 {
1946 ichac97MixerStore(pThis, AC97_PCM_Front_DAC_Rate, 0xbb80);
1947 ichac97MixerStore(pThis, AC97_PCM_LR_ADC_Rate, 0xbb80);
1948 ichac97OpenStream(pThis, PI_INDEX, 48000);
1949 ichac97OpenStream(pThis, PO_INDEX, 48000);
1950 }
1951 if (!(u32 & EACS_VRM))
1952 {
1953 ichac97MixerStore(pThis, AC97_MIC_ADC_Rate, 0xbb80);
1954 ichac97OpenStream(pThis, MC_INDEX, 48000);
1955 }
1956 LogFlowFunc(("Setting extended audio control to %#x\n", u32));
1957 ichac97MixerStore(pThis, AC97_Extended_Audio_Ctrl_Stat, u32);
1958 break;
1959 case AC97_PCM_Front_DAC_Rate:
1960 if (ichac97MixerLoad(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA)
1961 {
1962 ichac97MixerStore(pThis, index, u32);
1963 LogFlowFunc(("Set front DAC rate to %d\n", u32));
1964 ichac97OpenStream(pThis, PO_INDEX, u32);
1965 }
1966 else
1967 LogFlowFunc(("Attempt to set front DAC rate to %d, but VRA is not set\n", u32));
1968 break;
1969 case AC97_MIC_ADC_Rate:
1970 if (ichac97MixerLoad(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM)
1971 {
1972 ichac97MixerStore(pThis, index, u32);
1973 LogFlowFunc(("Set MIC ADC rate to %d\n", u32));
1974 ichac97OpenStream(pThis, MC_INDEX, u32);
1975 }
1976 else
1977 LogFlowFunc(("Attempt to set MIC ADC rate to %d, but VRM is not set\n", u32));
1978 break;
1979 case AC97_PCM_LR_ADC_Rate:
1980 if (ichac97MixerLoad(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA)
1981 {
1982 ichac97MixerStore(pThis, index, u32);
1983 LogFlowFunc(("Set front LR ADC rate to %d\n", u32));
1984 ichac97OpenStream(pThis, PI_INDEX, u32);
1985 }
1986 else
1987 LogFlowFunc(("Attempt to set LR ADC rate to %d, but VRA is not set\n", u32));
1988 break;
1989 default:
1990 LogFlowFunc(("U nam writew %#x <- %#x\n", Port, u32));
1991 ichac97MixerStore(pThis, index, u32);
1992 break;
1993 }
1994 break;
1995 }
1996
1997 case 4:
1998 {
1999 LogFlowFunc(("U nam writel %#x <- %#x\n", Port, u32));
2000 pThis->cas = 0;
2001 break;
2002 }
2003
2004 default:
2005 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
2006 break;
2007 }
2008
2009 return VINF_SUCCESS;
2010}
2011
2012
2013/**
2014 * @callback_method_impl{FNPCIIOREGIONMAP}
2015 */
2016static DECLCALLBACK(int) ichac97IOPortMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb,
2017 PCIADDRESSSPACE enmType)
2018{
2019 PPDMDEVINS pDevIns = pPciDev->pDevIns;
2020 PAC97STATE pThis = RT_FROM_MEMBER(pPciDev, AC97STATE, PciDev);
2021 RTIOPORT Port = (RTIOPORT)GCPhysAddress;
2022 int rc;
2023
2024 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2025 Assert(cb >= 0x20);
2026
2027 if (iRegion == 0)
2028 rc = PDMDevHlpIOPortRegister(pDevIns, Port, 256, pThis,
2029 ichac97IOPortNAMWrite, ichac97IOPortNAMRead,
2030 NULL, NULL, "ICHAC97 NAM");
2031 else
2032 rc = PDMDevHlpIOPortRegister(pDevIns, Port, 64, pThis,
2033 ichac97IOPortNABMWrite, ichac97IOPortNABMRead,
2034 NULL, NULL, "ICHAC97 NABM");
2035 if (RT_FAILURE(rc))
2036 return rc;
2037
2038 pThis->IOPortBase[iRegion] = Port;
2039 return VINF_SUCCESS;
2040}
2041
2042#ifdef IN_RING3
2043/**
2044 * @callback_method_impl{FNSSMDEVSAVEEXEC}
2045 */
2046static DECLCALLBACK(int) ichac97SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2047{
2048 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, AC97STATE *);
2049
2050 SSMR3PutU32(pSSM, pThis->glob_cnt);
2051 SSMR3PutU32(pSSM, pThis->glob_sta);
2052 SSMR3PutU32(pSSM, pThis->cas);
2053
2054 for (unsigned i = 0; i < RT_ELEMENTS(pThis->bm_regs); i++)
2055 {
2056 PAC97BMREG pReg = &pThis->bm_regs[i];
2057 SSMR3PutU32(pSSM, pReg->bdbar);
2058 SSMR3PutU8( pSSM, pReg->civ);
2059 SSMR3PutU8( pSSM, pReg->lvi);
2060 SSMR3PutU16(pSSM, pReg->sr);
2061 SSMR3PutU16(pSSM, pReg->picb);
2062 SSMR3PutU8( pSSM, pReg->piv);
2063 SSMR3PutU8( pSSM, pReg->cr);
2064 SSMR3PutS32(pSSM, pReg->bd_valid);
2065 SSMR3PutU32(pSSM, pReg->bd.addr);
2066 SSMR3PutU32(pSSM, pReg->bd.ctl_len);
2067 }
2068 SSMR3PutMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
2069
2070 uint8_t active[LAST_INDEX];
2071
2072#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2073 PAC97DRIVER pDrv;
2074 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
2075 {
2076 PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
2077 AssertPtr(pCon);
2078 active[PI_INDEX] = pCon->pfnIsActiveIn (pCon, pDrv->LineIn.pStrmIn) ? 1 : 0;
2079 active[PO_INDEX] = pCon->pfnIsActiveOut(pCon, pDrv->Out.pStrmOut) ? 1 : 0;
2080 active[MC_INDEX] = pCon->pfnIsActiveIn (pCon, pDrv->MicIn.pStrmIn) ? 1 : 0;
2081 }
2082#else
2083 active[PI_INDEX] = AUD_is_active_in( pThis->voice_pi) ? 1 : 0;
2084 active[PO_INDEX] = AUD_is_active_out(pThis->voice_po) ? 1 : 0;
2085 active[MC_INDEX] = AUD_is_active_in( pThis->voice_mc) ? 1 : 0;
2086#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2087
2088 SSMR3PutMem(pSSM, active, sizeof(active));
2089
2090 return VINF_SUCCESS;
2091}
2092
2093
2094/**
2095 * @callback_method_impl{FNSSMDEVLOADEXEC}
2096 */
2097static DECLCALLBACK(int) ichac97LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2098{
2099 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, AC97STATE *);
2100
2101 AssertMsgReturn (uVersion == AC97_SSM_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
2102 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
2103
2104 SSMR3GetU32(pSSM, &pThis->glob_cnt);
2105 SSMR3GetU32(pSSM, &pThis->glob_sta);
2106 SSMR3GetU32(pSSM, &pThis->cas);
2107
2108 for (unsigned i = 0; i < RT_ELEMENTS(pThis->bm_regs); i++)
2109 {
2110 PAC97BMREG pReg = &pThis->bm_regs[i];
2111 SSMR3GetU32(pSSM, &pReg->bdbar);
2112 SSMR3GetU8( pSSM, &pReg->civ);
2113 SSMR3GetU8( pSSM, &pReg->lvi);
2114 SSMR3GetU16(pSSM, &pReg->sr);
2115 SSMR3GetU16(pSSM, &pReg->picb);
2116 SSMR3GetU8( pSSM, &pReg->piv);
2117 SSMR3GetU8( pSSM, &pReg->cr);
2118 SSMR3GetS32(pSSM, &pReg->bd_valid);
2119 SSMR3GetU32(pSSM, &pReg->bd.addr);
2120 SSMR3GetU32(pSSM, &pReg->bd.ctl_len);
2121 }
2122
2123 SSMR3GetMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
2124 uint8_t active[LAST_INDEX];
2125 SSMR3GetMem(pSSM, active, sizeof(active));
2126
2127 ichac97RecordSelect(pThis, ichac97MixerLoad(pThis, AC97_Record_Select));
2128# define V_(a, b) ichac97SetVolume(pThis, a, b, ichac97MixerLoad(pThis, a))
2129# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2130 V_(AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME);
2131 V_(AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_PCM);
2132 V_(AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN);
2133# else
2134 V_(AC97_Master_Volume_Mute, AUD_MIXER_VOLUME);
2135 V_(AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM);
2136 V_(AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN);
2137# endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2138# undef V_
2139 ichac97ResetStreams(pThis, active);
2140
2141 pThis->bup_flag = 0;
2142 pThis->last_samp = 0;
2143
2144 return VINF_SUCCESS;
2145}
2146
2147
2148/**
2149 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2150 */
2151static DECLCALLBACK(void *) ichac97QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
2152{
2153 PAC97STATE pThis = RT_FROM_MEMBER(pInterface, AC97STATE, IBase);
2154 Assert(&pThis->IBase == pInterface);
2155
2156 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2157 return NULL;
2158}
2159
2160
2161/**
2162 * @interface_method_impl{PDMDEVREG,pfnReset}
2163 *
2164 * @remarks The original sources didn't install a reset handler, but it seems to
2165 * make sense to me so we'll do it.
2166 */
2167static DECLCALLBACK(void) ac97Reset(PPDMDEVINS pDevIns)
2168{
2169 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, AC97STATE *);
2170
2171 /*
2172 * Reset the device state (will need pDrv later).
2173 */
2174 ichac97ResetBMRegs(pThis, &pThis->bm_regs[0]);
2175 ichac97ResetBMRegs(pThis, &pThis->bm_regs[1]);
2176 ichac97ResetBMRegs(pThis, &pThis->bm_regs[2]);
2177
2178 /*
2179 * Reset the mixer too. The Windows XP driver seems to rely on
2180 * this. At least it wants to read the vendor id before it resets
2181 * the codec manually.
2182 */
2183 ichac97MixerReset(pThis);
2184}
2185
2186
2187/**
2188 * @interface_method_impl{PDMDEVREG,pfnDestruct}
2189 */
2190static DECLCALLBACK(int) ichac97Destruct(PPDMDEVINS pDevIns)
2191{
2192 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2193
2194 LogFlowFuncEnter();
2195
2196#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2197 PAC97DRIVER pDrv;
2198 while (!RTListIsEmpty(&pThis->lstDrv))
2199 {
2200 pDrv = RTListGetFirst(&pThis->lstDrv, AC97DRIVER, Node);
2201
2202 RTListNodeRemove(&pDrv->Node);
2203 RTMemFree(pDrv);
2204 }
2205
2206 if (pThis->pMixer)
2207 {
2208 AudioMixerDestroy(pThis->pMixer);
2209 pThis->pMixer = NULL;
2210 }
2211#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2212
2213 if (pThis->pvReadWriteBuf)
2214 {
2215 RTMemFree(pThis->pvReadWriteBuf);
2216 pThis->pvReadWriteBuf = NULL;
2217 pThis->cbReadWriteBuf = 0;
2218 }
2219
2220 LogFlowFuncLeave();
2221 return VINF_SUCCESS;
2222}
2223
2224
2225#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2226/**
2227 * Attach command.
2228 *
2229 * This is called to let the device attach to a driver for a specified LUN
2230 * during runtime. This is not called during VM construction, the device
2231 * constructor have to attach to all the available drivers.
2232 *
2233 * @returns VBox status code.
2234 * @param pDevIns The device instance.
2235 * @param uLUN The logical unit which is being detached.
2236 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2237 */
2238static DECLCALLBACK(int) ichac97Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
2239{
2240 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2241
2242 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
2243 ("AC'97 device does not support hotplugging\n"),
2244 VERR_INVALID_PARAMETER);
2245
2246 /*
2247 * Attach driver.
2248 */
2249 char *pszDesc = NULL;
2250 if (RTStrAPrintf(&pszDesc, "Audio driver port (AC'97) for LUN #%u", uLUN) <= 0)
2251 AssertMsgReturn(pszDesc,
2252 ("Not enough memory for AC'97 driver port description of LUN #%u\n", uLUN),
2253 VERR_NO_MEMORY);
2254
2255 int rc = PDMDevHlpDriverAttach(pDevIns, uLUN,
2256 &pThis->IBase, &pThis->pDrvBase, pszDesc);
2257 if (RT_SUCCESS(rc))
2258 {
2259 PAC97DRIVER pDrv = (PAC97DRIVER)RTMemAllocZ(sizeof(AC97DRIVER));
2260 if (pDrv)
2261 {
2262 pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIAUDIOCONNECTOR);
2263 AssertMsg(pDrv->pConnector != NULL,
2264 ("Configuration error: LUN #%u has no host audio interface, rc=%Rrc\n",
2265 uLUN, rc));
2266 pDrv->pAC97State = pThis;
2267 pDrv->uLUN = uLUN;
2268
2269 /*
2270 * For now we always set the driver at LUN 0 as our primary
2271 * host backend. This might change in the future.
2272 */
2273 if (pDrv->uLUN == 0)
2274 pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
2275
2276 LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
2277
2278 /* Attach to driver list. */
2279 RTListAppend(&pThis->lstDrv, &pDrv->Node);
2280 }
2281 else
2282 rc = VERR_NO_MEMORY;
2283 }
2284 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2285 {
2286 LogFunc(("No attached driver for LUN #%u\n", uLUN));
2287 }
2288 else if (RT_FAILURE(rc))
2289 AssertMsgFailed(("Failed to attach AC'97 LUN #%u (\"%s\"), rc=%Rrc\n",
2290 uLUN, pszDesc, rc));
2291
2292 RTStrFree(pszDesc);
2293
2294 LogFunc(("iLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
2295 return rc;
2296}
2297#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2298
2299
2300/**
2301 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2302 */
2303static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2304{
2305 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
2306
2307#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2308 /* NB: This must be done *before* any possible failure (and running the destructor). */
2309 RTListInit(&pThis->lstDrv);
2310#endif
2311
2312 Assert(iInstance == 0);
2313 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2314
2315 /*
2316 * Validations.
2317 */
2318 if (!CFGMR3AreValuesValid(pCfg, "Type\0"))
2319 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2320 N_("Invalid configuration for the AC'97 device"));
2321
2322 /*
2323 * Determine the chip type.
2324 */
2325 char szType[20];
2326 int rc = CFGMR3QueryStringDef(pCfg, "Type", &szType[0], sizeof(szType), "STAC9700");
2327 if (RT_FAILURE(rc))
2328 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2329 N_("AC'97 configuration error: Querying \"Type\" as string failed"));
2330
2331 /*
2332 * The AD1980 codec (with corresponding PCI subsystem vendor ID) is whitelisted
2333 * in the Linux kernel; Linux makes no attempt to measure the data rate and assumes
2334 * 48 kHz rate, which is exactly what we need.
2335 */
2336 bool fChipAD1980 = false;
2337 if (!strcmp(szType, "STAC9700"))
2338 fChipAD1980 = false;
2339 else if (!strcmp(szType, "AD1980"))
2340 fChipAD1980 = true;
2341 else
2342 {
2343 return PDMDevHlpVMSetError(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, RT_SRC_POS,
2344 N_("AC'97 configuration error: The \"Type\" value \"%s\" is unsupported"),
2345 szType);
2346 }
2347
2348 /*
2349 * Initialize data (most of it anyway).
2350 */
2351 pThis->pDevIns = pDevIns;
2352 /* IBase */
2353 pThis->IBase.pfnQueryInterface = ichac97QueryInterface;
2354
2355 /* PCI Device (the assertions will be removed later) */
2356 PCIDevSetVendorId (&pThis->PciDev, 0x8086); /* 00 ro - intel. */ Assert(pThis->PciDev.config[0x00] == 0x86); Assert(pThis->PciDev.config[0x01] == 0x80);
2357 PCIDevSetDeviceId (&pThis->PciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */ Assert(pThis->PciDev.config[0x02] == 0x15); Assert(pThis->PciDev.config[0x03] == 0x24);
2358 PCIDevSetCommand (&pThis->PciDev, 0x0000); /* 04 rw,ro - pcicmd. */ Assert(pThis->PciDev.config[0x04] == 0x00); Assert(pThis->PciDev.config[0x05] == 0x00);
2359 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);
2360 PCIDevSetRevisionId (&pThis->PciDev, 0x01); /* 08 ro - rid. */ Assert(pThis->PciDev.config[0x08] == 0x01);
2361 PCIDevSetClassProg (&pThis->PciDev, 0x00); /* 09 ro - pi. */ Assert(pThis->PciDev.config[0x09] == 0x00);
2362 PCIDevSetClassSub (&pThis->PciDev, 0x01); /* 0a ro - scc; 01 == Audio. */ Assert(pThis->PciDev.config[0x0a] == 0x01);
2363 PCIDevSetClassBase (&pThis->PciDev, 0x04); /* 0b ro - bcc; 04 == multimedia. */ Assert(pThis->PciDev.config[0x0b] == 0x04);
2364 PCIDevSetHeaderType (&pThis->PciDev, 0x00); /* 0e ro - headtyp. */ Assert(pThis->PciDev.config[0x0e] == 0x00);
2365 PCIDevSetBaseAddress (&pThis->PciDev, 0, /* 10 rw - nambar - native audio mixer base. */
2366 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);
2367 PCIDevSetBaseAddress (&pThis->PciDev, 1, /* 14 rw - nabmbar - native audio bus mastering. */
2368 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);
2369 PCIDevSetInterruptLine (&pThis->PciDev, 0x00); /* 3c rw. */ Assert(pThis->PciDev.config[0x3c] == 0x00);
2370 PCIDevSetInterruptPin (&pThis->PciDev, 0x01); /* 3d ro - INTA#. */ Assert(pThis->PciDev.config[0x3d] == 0x01);
2371
2372 if (fChipAD1980)
2373 {
2374 PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x1028); /* 2c ro - Dell.) */
2375 PCIDevSetSubSystemId (&pThis->PciDev, 0x0177); /* 2e ro. */
2376 }
2377 else
2378 {
2379 PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x8086); /* 2c ro - Intel.) */
2380 PCIDevSetSubSystemId (&pThis->PciDev, 0x0000); /* 2e ro. */
2381 }
2382
2383 /*
2384 * Register the PCI device, it's I/O regions, the timer and the
2385 * saved state item.
2386 */
2387 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
2388 if (RT_FAILURE (rc))
2389 return rc;
2390
2391 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 256, PCI_ADDRESS_SPACE_IO, ichac97IOPortMap);
2392 if (RT_FAILURE (rc))
2393 return rc;
2394
2395 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 64, PCI_ADDRESS_SPACE_IO, ichac97IOPortMap);
2396 if (RT_FAILURE (rc))
2397 return rc;
2398
2399 rc = PDMDevHlpSSMRegister(pDevIns, AC97_SSM_VERSION, sizeof(*pThis), ichac97SaveExec, ichac97LoadExec);
2400 if (RT_FAILURE (rc))
2401 return rc;
2402
2403 /*
2404 * Attach driver.
2405 */
2406#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2407 uint8_t uLUN;
2408 for (uLUN = 0; uLUN < UINT8_MAX; uLUN)
2409 {
2410 LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
2411 rc = ichac97Attach(pDevIns, uLUN, PDM_TACH_FLAGS_NOT_HOT_PLUG);
2412 if (RT_FAILURE(rc))
2413 {
2414 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2415 rc = VINF_SUCCESS;
2416 break;
2417 }
2418
2419 uLUN++;
2420 }
2421
2422 LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
2423#else
2424 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Audio Driver Port");
2425 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2426 LogFunc(("ac97: No attached driver!\n"));
2427 else if (RT_FAILURE(rc))
2428 {
2429 AssertMsgFailed(("Failed to attach AC97 LUN #0! rc=%Rrc\n", rc));
2430 return rc;
2431 }
2432#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2433
2434#ifndef VBOX_WITH_PDM_AUDIO_DRIVER
2435 AUD_register_card("ICH0", &pThis->card);
2436#endif
2437 ac97Reset(pDevIns);
2438
2439#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2440 PAC97DRIVER pDrv;
2441 uLUN = 0;
2442 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
2443 {
2444 if (!pDrv->pConnector->pfnIsInputOK(pDrv->pConnector, pDrv->LineIn.pStrmIn))
2445 LogRel(("AC97: WARNING: Unable to open PCM line input for LUN #%RU32!\n", uLUN));
2446 if (!pDrv->pConnector->pfnIsOutputOK(pDrv->pConnector, pDrv->Out.pStrmOut))
2447 LogRel(("AC97: WARNING: Unable to open PCM output for LUN #%RU32!\n", uLUN));
2448 if (!pDrv->pConnector->pfnIsInputOK(pDrv->pConnector, pDrv->MicIn.pStrmIn))
2449 LogRel(("AC97: WARNING: Unable to open PCM microphone input for LUN #%RU32!\n", uLUN));
2450
2451 uLUN++;
2452 }
2453
2454 RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
2455 {
2456 /*
2457 * Only primary drivers are critical for the VM to run. Everything else
2458 * might not worth showing an own error message box in the GUI.
2459 */
2460 if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
2461 continue;
2462
2463 PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
2464 AssertPtr(pCon);
2465 if ( !pCon->pfnIsInputOK (pCon, pDrv->LineIn.pStrmIn)
2466 && !pCon->pfnIsOutputOK(pCon, pDrv->Out.pStrmOut)
2467 && !pCon->pfnIsInputOK (pCon, pDrv->MicIn.pStrmIn))
2468 {
2469 LogRel(("AC97: Falling back to NULL driver\n"));
2470
2471 /* Was not able initialize *any* stream.
2472 * Select the NULL audio driver instead. */
2473 pCon->pfnCloseIn (pCon, pDrv->LineIn.pStrmIn);
2474 pCon->pfnCloseOut(pCon, pDrv->Out.pStrmOut);
2475 pCon->pfnCloseIn (pCon, pDrv->MicIn.pStrmIn);
2476
2477 pDrv->Out.pStrmOut = NULL;
2478 pDrv->LineIn.pStrmIn = NULL;
2479 pDrv->MicIn.pStrmIn = NULL;
2480
2481 pCon->pfnInitNull(pCon);
2482 ac97Reset(pDevIns);
2483
2484 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2485 N_("No audio devices could be opened. Selecting the NULL audio backend "
2486 "with the consequence that no sound is audible"));
2487 }
2488 else if ( !pCon->pfnIsInputOK (pCon, pDrv->LineIn.pStrmIn)
2489 || !pCon->pfnIsOutputOK(pCon, pDrv->Out.pStrmOut)
2490 || !pCon->pfnIsInputOK (pCon, pDrv->MicIn.pStrmIn))
2491 {
2492 char szMissingStreams[255];
2493 size_t len = 0;
2494 if (!pCon->pfnIsInputOK (pCon, pDrv->LineIn.pStrmIn))
2495 len = RTStrPrintf(szMissingStreams,
2496 sizeof(szMissingStreams), "PCM Input");
2497 if (!pCon->pfnIsOutputOK(pCon, pDrv->Out.pStrmOut))
2498 len += RTStrPrintf(szMissingStreams + len,
2499 sizeof(szMissingStreams) - len, len ? ", PCM Output" : "PCM Output");
2500 if (!pCon->pfnIsInputOK (pCon, pDrv->MicIn.pStrmIn))
2501 len += RTStrPrintf(szMissingStreams + len,
2502 sizeof(szMissingStreams) - len, len ? ", PCM Microphone" : "PCM Microphone");
2503
2504 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2505 N_("Some AC'97 audio streams (%s) could not be opened. Guest applications generating audio "
2506 "output or depending on audio input may hang. Make sure your host audio device "
2507 "is working properly. Check the logfile for error messages of the audio "
2508 "subsystem"), szMissingStreams);
2509 }
2510 }
2511#else
2512 if (!AUD_is_host_voice_in_ok(pThis->voice_pi))
2513 LogRel(("AC97: WARNING: Unable to open PCM IN!\n"));
2514 if (!AUD_is_host_voice_in_ok(pThis->voice_mc))
2515 LogRel(("AC97: WARNING: Unable to open PCM MC!\n"));
2516 if (!AUD_is_host_voice_out_ok(pThis->voice_po))
2517 LogRel(("AC97: WARNING: Unable to open PCM OUT!\n"));
2518
2519 if ( !AUD_is_host_voice_in_ok( pThis->voice_pi)
2520 && !AUD_is_host_voice_out_ok(pThis->voice_po)
2521 && !AUD_is_host_voice_in_ok( pThis->voice_mc))
2522 {
2523 AUD_close_in(&pThis->card, pThis->voice_pi);
2524 AUD_close_out(&pThis->card, pThis->voice_po);
2525 AUD_close_in(&pThis->card, pThis->voice_mc);
2526
2527 pThis->voice_po = NULL;
2528 pThis->voice_pi = NULL;
2529 pThis->voice_mc = NULL;
2530 AUD_init_null();
2531 ac97Reset(pDevIns);
2532
2533 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2534 N_("No audio devices could be opened. Selecting the NULL audio backend "
2535 "with the consequence that no sound is audible"));
2536 }
2537 else if ( !AUD_is_host_voice_in_ok( pThis->voice_pi)
2538 || !AUD_is_host_voice_out_ok(pThis->voice_po)
2539 || !AUD_is_host_voice_in_ok( pThis->voice_mc))
2540 {
2541 char szMissingVoices[128];
2542 size_t len = 0;
2543 if (!AUD_is_host_voice_in_ok(pThis->voice_pi))
2544 len = RTStrPrintf(szMissingVoices, sizeof(szMissingVoices), "PCM_in");
2545 if (!AUD_is_host_voice_out_ok(pThis->voice_po))
2546 len += RTStrPrintf(szMissingVoices + len, sizeof(szMissingVoices) - len, len ? ", PCM_out" : "PCM_out");
2547 if (!AUD_is_host_voice_in_ok(pThis->voice_mc))
2548 len += RTStrPrintf(szMissingVoices + len, sizeof(szMissingVoices) - len, len ? ", PCM_mic" : "PCM_mic");
2549
2550 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2551 N_("Some audio devices (%s) could not be opened. Guest applications generating audio "
2552 "output or depending on audio input may hang. Make sure your host audio device "
2553 "is working properly. Check the logfile for error messages of the audio "
2554 "subsystem"), szMissingVoices);
2555 }
2556#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2557
2558 if (RT_SUCCESS(rc))
2559 {
2560 pThis->cbReadWriteBuf = _4K; /** @todo Make this configurable. */
2561 pThis->pvReadWriteBuf = (uint8_t *)RTMemAllocZ(pThis->cbReadWriteBuf);
2562 if (!pThis->pvReadWriteBuf)
2563 rc = VERR_NO_MEMORY;
2564 }
2565
2566#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2567 if (RT_SUCCESS(rc))
2568 {
2569 /* Start the emulation timer. */
2570 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ichac97Timer, pThis,
2571 TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchAc97", &pThis->pTimer);
2572 AssertRCReturn(rc, rc);
2573
2574 if (RT_SUCCESS(rc))
2575 {
2576 pThis->uTicks = PDMDevHlpTMTimeVirtGetFreq(pDevIns) / 200; /** Hz. @todo Make this configurable! */
2577 if (pThis->uTicks < 100)
2578 pThis->uTicks = 100;
2579 LogFunc(("Timer ticks=%RU64\n", pThis->uTicks));
2580
2581 /* Fire off timer. */
2582 TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->uTicks);
2583 }
2584 }
2585
2586# ifdef VBOX_WITH_STATISTICS
2587 if (RT_SUCCESS(rc))
2588 {
2589 /*
2590 * Register statistics.
2591 */
2592 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer, STAMTYPE_PROFILE, "/Devices/AC97/Timer", STAMUNIT_TICKS_PER_CALL, "Profiling ichac97Timer.");
2593 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, "/Devices/AC97/BytesRead" , STAMUNIT_BYTES, "Bytes read from AC97 emulation.");
2594 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "/Devices/AC97/BytesWritten", STAMUNIT_BYTES, "Bytes written to AC97 emulation.");
2595 }
2596# endif
2597
2598#endif
2599
2600 return VINF_SUCCESS;
2601}
2602
2603/**
2604 * The device registration structure.
2605 */
2606const PDMDEVREG g_DeviceICHAC97 =
2607{
2608 /* u32Version */
2609 PDM_DEVREG_VERSION,
2610 /* szName */
2611 "ichac97",
2612 /* szRCMod */
2613 "",
2614 /* szR0Mod */
2615 "",
2616 /* pszDescription */
2617 "ICH AC'97 Audio Controller",
2618 /* fFlags */
2619 PDM_DEVREG_FLAGS_DEFAULT_BITS,
2620 /* fClass */
2621 PDM_DEVREG_CLASS_AUDIO,
2622 /* cMaxInstances */
2623 1,
2624 /* cbInstance */
2625 sizeof(AC97STATE),
2626 /* pfnConstruct */
2627 ichac97Construct,
2628 /* pfnDestruct */
2629 ichac97Destruct,
2630 /* pfnRelocate */
2631 NULL,
2632 /* pfnMemSetup */
2633 NULL,
2634 /* pfnPowerOn */
2635 NULL,
2636 /* pfnReset */
2637 ac97Reset,
2638 /* pfnSuspend */
2639 NULL,
2640 /* pfnResume */
2641 NULL,
2642 /* pfnAttach */
2643 NULL,
2644 /* pfnDetach */
2645 NULL,
2646 /* pfnQueryInterface. */
2647 NULL,
2648 /* pfnInitComplete */
2649 NULL,
2650 /* pfnPowerOff */
2651 NULL,
2652 /* pfnSoftReset */
2653 NULL,
2654 /* u32VersionEnd */
2655 PDM_DEVREG_VERSION
2656};
2657
2658#endif /* !IN_RING3 */
2659#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