VirtualBox

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

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

PDM/Audio: Removed old audio architecture.

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