VirtualBox

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

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

Audio: Remove DEV_AUDIO logging group and split it up into per device and driver groups for finer grained logging

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

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