VirtualBox

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

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

Todo.

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