VirtualBox

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

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

Not necessary.

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