VirtualBox

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

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

Audio: Volume handling rework (see #5964).

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