VirtualBox

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

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

PDM/Audio: Build fix; forgot some files.

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

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