VirtualBox

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

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

Audio: Spelling, Hungarian fixes.

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