VirtualBox

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

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

PDM/Audio: Added volume through virtual mixer.

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