DevIchAc97.cpp revision 2b114c590cf5a19f8047cd7bde9c7e5ae00aa22b
682a27d94b9116c719038882487b99053985f91avboxsync * DevIchAc97 - VBox ICH AC97 Audio Controller.
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2014 Oracle Corporation
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * available from http://www.virtualbox.org. This file is free software;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * you can redistribute it and/or modify it under the terms of the GNU
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * General Public License (GPL) as published by the Free Software
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync/*******************************************************************************
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync* Header Files *
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync*******************************************************************************/
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync extern "C" {
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#ifdef LOG_GROUP
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync #undef LOG_GROUP
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#define LOG_GROUP LOG_GROUP_DEV_AUDIO
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync/*******************************************************************************
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync* Defined Constants And Macros *
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync*******************************************************************************/
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync//#define USE_MIXER
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync//#define DEBUG_LUN
4c953c3c459d80bc3e31a0a65a9dc0463f340e6bvboxsync#endif /* DEBUG */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#define SR_BCIS RT_BIT(3) /* rwc, buffer completion interrupt status */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#define SR_LVBCI RT_BIT(2) /* rwc, last valid buffer completion interrupt */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#define SR_CELV RT_BIT(1) /* ro, current equals last valid */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#define SR_DCH RT_BIT(0) /* ro, controller halted */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync/** @name Buffer Descriptor
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#define BD_IOC RT_BIT(31) /**< Interrupt on Completion */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#define BD_BUP RT_BIT(30) /**< Buffer Underrun Policy */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync/*******************************************************************************
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync* Structures and Typedefs *
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync*******************************************************************************/
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Buffer descriptor.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsynctypedef struct BD
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync uint32_t bdbar; /**< rw 0, buffer descriptor list base address register */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync uint16_t picb; /**< ro 0, position in current buffer */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync/** Pointer to a AC97 bus master register. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Struct for maintaining a host backend driver.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsynctypedef struct AC97DRIVER
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** Pointer to AC97 controller (state). */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** Driver flags. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** LUN # to which this driver has been assigned. */
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync /** Audio connector interface to the underlying
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * host backend. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** PCM input stream. */
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync /** Mixer handle for input stream. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** PCM output stream. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** PCM microphone input stream. */
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync /** Mixer handle for output stream. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync/** Pointer to a AC97 driver. */
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsynctypedef struct AC97STATE
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** The PCI device state. */
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync /** Audio stuff. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** Global Control (Bus Master Control Register) */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** Global Status (Bus Master Control Register) */
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync /** Codec Access Semaphore Register (Bus Master Control Register) */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** Bus Master Control Registers for PCM in, PCM out, and Mic in */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** Number of active + allocated LUNs. Each
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * LUN has an AC'97 driver assigned. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** Array of active AC'97 drivers. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** The device' software mixer. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** Audio sink for line input. */
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync /** Audio sink for microphone input. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** PCM in */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** PCM out */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** Mic in */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** Pointer to the device instance. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** Pointer to the attached audio driver. */
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync /** The base interface for LUN\#0. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** Base port of the I/O space region. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync/** Pointer to the AC97 device state. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#define ICHAC97STATE_2_DEVINS(a_pAC97) ((a_pAC97)->pDevIns)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97OutputCallback(void *pvContext, uint32_t cbFree);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97InputCallback(void *pvContext, uint32_t cbAvail);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97MicInCallback(void *pvContext, uint32_t cbAvail);
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsyncstatic void ichac97OutputCallback(void *pvContext, int cbFree);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97InputCallback(void *pvContext, int cbAvail);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97MicInCallback(void *pvContext, int cbAvail);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync/** Fetches the buffer descriptor at _CIV. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97FetchBufDesc(PAC97STATE pThis, PAC97BMREG pReg)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync PDMDevHlpPhysRead(pDevIns, pReg->bdbar + pReg->civ * 8, &u32[0], sizeof(u32));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#if !defined(RT_ARCH_X86) && !defined(RT_ARCH_AMD64)
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync# error Please adapt the code (audio buffers are little endian)!
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync pReg->bd.ctl_len & 0xffff, (pReg->bd.ctl_len & 0xffff) << 1));
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync * Update the BM status register
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97UpdateStatus(PAC97STATE pThis, PAC97BMREG pReg, uint32_t new_sr)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync static uint32_t const masks[] = { GS_PIINT, GS_POINT, GS_MINT };
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** @todo is IRQ deasserted when only one of status bits is cleared? */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync else if ((new_mask & SR_LVBCI) && (pReg->cr & CR_LVBIE))
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync else if ((new_mask & SR_BCIS) && (pReg->cr & CR_IOCE))
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("IOC%d LVB%d sr=%#x event=%d level=%d\n",
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pReg->sr & SR_BCIS, pReg->sr & SR_LVBCI, pReg->sr, event, level));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97StreamSetActive(PAC97STATE pThis, int bm_index, int on)
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->paDrv[lun]->pConnector->pfnEnableOut(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync case PI_INDEX: AUD_set_active_in( pThis->voice_pi, on); break;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync case PO_INDEX: AUD_set_active_out(pThis->voice_po, on); break;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync case MC_INDEX: AUD_set_active_in( pThis->voice_mc, on); break;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync default: AssertFailed (); break;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97ResetBMRegs(PAC97STATE pThis, PAC97BMREG pReg)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** @todo do we need to do that? */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync ichac97StreamSetActive(pThis, pReg - pThis->bm_regs, 0);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97MixerStore(PAC97STATE pThis, uint32_t i, uint16_t v)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("mixer_store: index %d out of bounds %d\n", i, sizeof(pThis->mixer_data)));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic uint16_t ichac97MixerLoad(PAC97STATE pThis, uint32_t i)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("mixer_store: index %d out of bounds %d\n", i, sizeof(pThis->mixer_data)));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync val = pThis->mixer_data[i + 0] | (pThis->mixer_data[i + 1] << 8);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97OpenStream(PAC97STATE pThis, int index, uint16_t freq)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("index=%d, freq=%RU16\n", index, freq));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] ac97.pi", lun) <= 0)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = pThis->paDrv[lun]->pConnector->pfnOpenIn(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync ichac97InputCallback, pThis->paDrv[lun] /* pvContext */,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("LUN#%RU8: Opened line input with rc=%Rrc\n", lun, rc));
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync audioMixerRemoveStream(pThis->pSinkLineIn, pThis->paDrv[lun]->phStrmIn);
ebd35513cc8c7c67273191d51285629d77a1f736vboxsync pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmIn,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync 0 /* uFlags */,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] ac97.po", lun) <= 0)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = pThis->paDrv[lun]->pConnector->pfnOpenOut(pThis->paDrv[lun]->pConnector, pszDesc,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync ichac97OutputCallback, pThis->paDrv[lun] /* pvContext */,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("LUN#%RU8: Opened output with rc=%Rrc\n", lun, rc));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] ac97.mc", lun) <= 0)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = pThis->paDrv[lun]->pConnector->pfnOpenIn(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync ichac97MicInCallback, pThis->paDrv[lun] /* pvContext */,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("LUN#%RU8: Opened mic input with rc=%Rrc\n", lun, rc));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync audioMixerRemoveStream(pThis->pSinkMicIn, pThis->paDrv[lun]->phStrmMic);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmMic,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync 0 /* uFlags */,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("Unsupported index %d\n", index));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->paDrv[lun]->pConnector->pfnCloseIn(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->paDrv[lun]->pConnector->pfnCloseOut(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->paDrv[lun]->pConnector->pfnCloseIn(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("Unsupported index %d\n", index));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->voice_pi = AUD_open_in(&pThis->card, pThis->voice_pi, "ac97.pi", pThis, ichac97InputCallback, &as);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogRel(("AC97: open PI freq=%d (%s)\n", freq, pThis->voice_pi ? "ok" : "FAIL"));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = pThis->voice_pi ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->voice_po = AUD_open_out(&pThis->card, pThis->voice_po, "ac97.po", pThis, ichac97OutputCallback, &as);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogRel(("AC97: open PO freq=%d (%s)\n", freq, pThis->voice_po ? "ok" : "FAIL"));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = pThis->voice_po ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->voice_mc = AUD_open_in(&pThis->card, pThis->voice_mc, "ac97.mc", pThis, ichac97MicInCallback, &as);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogRel(("AC97: open MC freq=%d (%s)\n", freq, pThis->voice_mc ? "ok" : "FAIL"));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = pThis->voice_mc ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync/** @todo r=andy D'oh, pretty bad argument handling -- fix this! */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97ResetStreams(PAC97STATE pThis, uint8_t active[LAST_INDEX])
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync uint16_t uFreq = ichac97MixerLoad(pThis, AC97_PCM_LR_ADC_Rate);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("Input ADC uFreq=%RU16, fEnabled=%RTbool\n", uFreq, fEnable));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AUD_set_active_in(pThis->voice_pi, active[PI_INDEX]);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync uFreq = ichac97MixerLoad(pThis, AC97_PCM_Front_DAC_Rate);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("Output DAC uFreq=%RU16, fEnabled=%RTbool\n", uFreq, fEnable));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->paDrv[lun]->pConnector->pfnEnableOut(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AUD_set_active_out(pThis->voice_po, active[PO_INDEX]);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync uFreq = ichac97MixerLoad(pThis, AC97_MIC_ADC_Rate);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("Mic ADC uFreq=%RU16, fEnabled=%RTbool\n", uFreq, fEnable));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AUD_set_active_in(pThis->voice_mc, active[MC_INDEX]);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97SetVolume(PAC97STATE pThis, int index, PDMAUDIOMIXERCTL mt, uint32_t val)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97SetVolume(PAC97STATE pThis, int index, audmixerctl_t mt, uint32_t val)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->paDrv[lun]->pConnector->pfnIsSetOutVolume(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AUD_set_volume_out(pThis->voice_po, mute, lvol, rvol);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync# endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** @todo In SetVolume no passing audmixerctl_in as its not used in DrvAudio.c */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->paDrv[lun]->pConnector->pfnSetVolume(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync# endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#else /* !SOFT_VOLUME */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pThis->paDrv[lun]->pConnector->pfnSetVolume(pThis->paDrv[lun]->pConnector,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync# endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#endif /* SOFT_VOLUME */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * From AC'97 SoundMax Codec AD1981A: "Because AC '97 defines 6-bit volume registers, to
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * maintain compatibility whenever the D5 or D13 bits are set to `1,' their respective
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * lower five volume bits are automatically set to `1' by the Codec logic. On readback,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * all lower 5 bits will read ones whenever these bits are set to `1.'"
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Linux ALSA depends on this behavior.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync val |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync val |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic PDMAUDIORECSOURCE ichac97IndextoRecSource(uint8_t i)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync case REC_LINE_IN: return PDMAUDIORECSOURCE_LINE_IN;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("Unknown record source %d, using MIC\n", i));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic uint8_t ichac97RecSourceToIndex(PDMAUDIORECSOURCE rs)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync case PDMAUDIORECSOURCE_LINE_IN: return REC_LINE_IN;
dced478b440a327fb550155c0f73c1ac968ad93bvboxsync LogFlowFunc(("Unknown audio recording source %d using MIC\n", rs));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic void ichac97RecordSelect(PAC97STATE pThis, uint32_t val)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync PDMAUDIORECSOURCE ars = ichac97IndextoRecSource(rs);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync PDMAUDIORECSOURCE als = ichac97IndextoRecSource(ls);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync //AUD_set_record_source(&als, &ars);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync ichac97MixerStore(pThis, AC97_Record_Select, rs | (ls << 8));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#endif /* USE_MIXER */
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync ichac97MixerStore(pThis, AC97_Reset , 0x0000); /* 6940 */
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync ichac97MixerStore(pThis, AC97_Master_Volume_Mono_Mute , 0x8000);
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync ichac97MixerStore(pThis, AC97_PC_BEEP_Volume_Mute , 0x0000);
62592281fc2971692c6755401b5ce1ed61b96d7cvboxsync ichac97MixerStore(pThis, AC97_Phone_Volume_Mute , 0x8008);
62592281fc2971692c6755401b5ce1ed61b96d7cvboxsync ichac97MixerStore(pThis, AC97_Mic_Volume_Mute , 0x8008);
62592281fc2971692c6755401b5ce1ed61b96d7cvboxsync ichac97MixerStore(pThis, AC97_CD_Volume_Mute , 0x8808);
12767477bc2dbc7815e4784576a15c990f5590d3vboxsync ichac97MixerStore(pThis, AC97_Aux_Volume_Mute , 0x8808);
12767477bc2dbc7815e4784576a15c990f5590d3vboxsync ichac97MixerStore(pThis, AC97_Record_Gain_Mic_Mute , 0x8000);
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync ichac97MixerStore(pThis, AC97_General_Purpose , 0x0000);
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync ichac97MixerStore(pThis, AC97_3D_Control , 0x0000);
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync ichac97MixerStore(pThis, AC97_Powerdown_Ctrl_Stat , 0x000f);
e61cd03db2217b7ec7467065af02d7ea7549149evboxsync * Sigmatel 9700 (STAC9700)
aeca728c901587edda5cdc79092a6432ad85d3e7vboxsync ichac97MixerStore(pThis, AC97_Vendor_ID1 , 0x8384);
aeca728c901587edda5cdc79092a6432ad85d3e7vboxsync ichac97MixerStore(pThis, AC97_Vendor_ID2 , 0x7600); /* 7608 */
e61cd03db2217b7ec7467065af02d7ea7549149evboxsync ichac97MixerStore(pThis, AC97_Extended_Audio_ID , 0x0809);
e61cd03db2217b7ec7467065af02d7ea7549149evboxsync ichac97MixerStore(pThis, AC97_Extended_Audio_Ctrl_Stat, 0x0009);
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync ichac97MixerStore(pThis, AC97_PCM_Front_DAC_Rate , 0xbb80);
e61cd03db2217b7ec7467065af02d7ea7549149evboxsync ichac97MixerStore(pThis, AC97_PCM_Surround_DAC_Rate , 0xbb80);
aeca728c901587edda5cdc79092a6432ad85d3e7vboxsync ichac97MixerStore(pThis, AC97_PCM_LFE_DAC_Rate , 0xbb80);
aeca728c901587edda5cdc79092a6432ad85d3e7vboxsync ichac97MixerStore(pThis, AC97_PCM_LR_ADC_Rate , 0xbb80);
e61cd03db2217b7ec7467065af02d7ea7549149evboxsync ichac97MixerStore(pThis, AC97_MIC_ADC_Rate , 0xbb80);
e61cd03db2217b7ec7467065af02d7ea7549149evboxsync ichac97SetVolume(pThis, AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME, 0x8000);
e61cd03db2217b7ec7467065af02d7ea7549149evboxsync ichac97SetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_PCM, 0x8808);
e61cd03db2217b7ec7467065af02d7ea7549149evboxsync ichac97SetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808);
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync ichac97SetVolume(pThis, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME, 0x8000);
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync ichac97SetVolume(pThis, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM, 0x8808);
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync ichac97SetVolume(pThis, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808);
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsync ichac97MixerStore(pThis, AC97_Master_Volume_Mute, 0x8000);
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsync ichac97MixerStore(pThis, AC97_PCM_Out_Volume_Mute, 0x8808);
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsync ichac97MixerStore(pThis, AC97_Line_In_Volume_Mute, 0x8808);
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync int rc2 = audioMixerCreate("AC'97 Mixer", 0 /* uFlags */,
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync rc2 = audioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* Add all required audio sinks. */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync rc2 = audioMixerAddSink(pThis->pMixer, "[Recording] Line In",
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc2 = audioMixerAddSink(pThis->pMixer, "[Recording] Microphone In",
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* Reset all streams. */
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsyncstatic int ichac97WriteAudio(PAC97STATE pThis, PAC97BMREG pReg, int max, int *stop)
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync uint32_t temp = RT_MIN((uint32_t)pReg->picb << 1, (uint32_t)max);
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync PDMDevHlpPhysRead(pDevIns, addr, tmpbuf, to_copy); /** @todo Check rc? */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* Just multiplex the output to the connected backends.
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsync * No need to utilize the virtual mixer here (yet). */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = pThis->paDrv[lun]->pConnector->pfnWrite(pThis->paDrv[lun]->pConnector,
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync copied = AUD_write(pThis->voice_po, tmpbuf, to_copy);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync LogFlowFunc(("to_copy=%RU32, copied=%RU32, temp=%RU32, temp_left=%RU32\n",
9ee72227058430bcead5831131741b5dc1601f00vboxsync pThis->last_samp = *(uint32_t *)&tmpbuf[to_copy - 4];
9ee72227058430bcead5831131741b5dc1601f00vboxsyncstatic void ichac97WriteBUP(PAC97STATE pThis, int elapsed)
62592281fc2971692c6755401b5ce1ed61b96d7cvboxsync unsigned int i;
62592281fc2971692c6755401b5ce1ed61b96d7cvboxsync unsigned int temp = RT_MIN((unsigned int)elapsed, sizeof(pThis->silence));
9ee72227058430bcead5831131741b5dc1601f00vboxsync int rc2 = pThis->paDrv[lun]->pConnector->pfnWrite(pThis->paDrv[lun]->pConnector,
9ee72227058430bcead5831131741b5dc1601f00vboxsync copied = AUD_write(pThis->voice_po, pThis->silence, temp);
62592281fc2971692c6755401b5ce1ed61b96d7cvboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsyncstatic int ichac97ReadAudio(PAC97STATE pThis, PAC97BMREG pReg, int max, int *stop)
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync /* Select audio sink to process. */
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync PAUDMIXSINK pSink = (pReg - pThis->bm_regs) == MC_INDEX
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync uint32_t cbToRead = RT_MIN(pReg->picb << 1, cbMixBuf);
60124f8bdc1927b7bb28d8bb4fad7bbdd93811c9vboxsync uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbMixBuf);
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync rc = audioMixerProcessSinkIn(pSink, pvMixBuf, cbToRead, &cbRead);
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync PDMDevHlpPCIPhysWrite(pDevIns, pReg->bd.addr, pvMixBuf, cbRead);
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync SWVoiceIn *voice = (pReg - pThis->bm_regs) == MC_INDEX ? pThis->voice_mc : pThis->voice_pi;
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync PDMDevHlpPCIPhysWrite(pDevIns, addr, tmpbuf, acquired);
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsyncstatic void ichac97TransferAudio(PAC97DRIVER pDrv, int index, int elapsed)
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsyncstatic void ichac97TransferAudio(PAC97STATE pThis, int index, int elapsed)
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync if (pDrv->uLUN != 0) /* Only LUN 0 can write and read from the device. */
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync /** @todo Fix this limitation by implementing a virtual mixer. */
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync LogFlowFunc(("Invalid buffer descriptor, fetching next one ...\n"));
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync if (!pReg->picb) /* Got a new buffer descriptor, that is, the position is 0? */
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync LogFlowFunc(("Fresh buffer descriptor %d is empty, addr=%#x, len=%#x, skipping\n",
60124f8bdc1927b7bb28d8bb4fad7bbdd93811c9vboxsync temp = ichac97WriteAudio(pThis, pReg, elapsed, &stop);
62592281fc2971692c6755401b5ce1ed61b96d7cvboxsync Assert((temp & 1) == 0); /* Else the following shift won't work */
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync temp = ichac97ReadAudio(pThis, pReg, elapsed, &stop);
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync Assert((temp & 1) == 0); /* Else the following shift won't work */
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync AssertMsgFailed(("Index %d not supported\n", index));
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync LogFlowFunc(("Underrun civ (%d) == lvi (%d)\n", pReg->civ, pReg->lvi));
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync pThis->bup_flag = (pReg->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsyncstatic void ichac97InputCallback(void *pvContext, uint32_t cbAvail)
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsyncstatic void ichac97InputCallback(void *pvContext, int cbAvail)
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync ichac97TransferAudio((AC97STATE *)pvContext, PI_INDEX, cbAvail);
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsyncstatic void ichac97MicInCallback(void *pvContext, uint32_t cbAvail)
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsyncstatic void ichac97MicInCallback(void *pvContext, int cbAvail)
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync ichac97TransferAudio((AC97STATE *)pvContext, MC_INDEX, cbAvail);
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsyncstatic void ichac97OutputCallback(void *pvContext, uint32_t cbFree)
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsyncstatic void ichac97OutputCallback(void *pvContext, int cbFree)
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync ichac97TransferAudio((AC97STATE *)pvContext, PO_INDEX, cbFree);
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync * @callback_method_impl{FNIOMIOPORTIN}
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsyncstatic DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* Codec Access Semaphore Register */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* Current Index Value Register */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("CIV[%d] -> %#x\n", GET_BM(index), *pu32));
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync /* Last Valid Index Register */
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync LogFlowFunc(("LVI[%d] -> %#x\n", GET_BM(index), *pu32));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* Prefetched Index Value Register */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync LogFlowFunc(("PIV[%d] -> %#x\n", GET_BM(index), *pu32));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* Control Register */
e68e2431dbeeab80792bbd9b1c64a68fc3358d0evboxsync LogFlowFunc(("CR[%d] -> %#x\n", GET_BM(index), *pu32));
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsync /* Status Register (lower part) */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync LogFlowFunc(("SRb[%d] -> %#x\n", GET_BM(index), *pu32));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync LogFlowFunc(("U nabm readb %#x -> %#x\n", Port, *pu32));
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsync /* Status Register */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync LogFlowFunc(("SR[%d] -> %#x\n", GET_BM(index), *pu32));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* Position in Current Buffer Register */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync LogFlowFunc(("PICB[%d] -> %#x\n", GET_BM(index), *pu32));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync LogFlowFunc(("U nabm readw %#x -> %#x\n", Port, *pu32));
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsync /* Buffer Descriptor Base Address Register */
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsync LogFlowFunc(("BMADDR[%d] -> %#x\n", GET_BM(index), *pu32));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* 32-bit access: Current Index Value Register +
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Last Valid Index Register +
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Status Register */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync *pu32 = pReg->civ | (pReg->lvi << 8) | (pReg->sr << 16);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync LogFlowFunc(("CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM(index), pReg->civ, pReg->lvi, pReg->sr));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* 32-bit access: Position in Current Buffer Register +
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Prefetched Index Value Register +
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Control Register */
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync *pu32 = pReg->picb | (pReg->piv << 16) | (pReg->cr << 24);
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsync LogFlowFunc(("PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM(index), *pu32, pReg->picb, pReg->piv, pReg->cr));
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* Global Control */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* Global Status */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("U nabm readl %#x -> %#x\n", Port, *pu32));
84c5015eccf5ba071c02e51da99b4d7593f690fevboxsync * @callback_method_impl{FNIOMIOPORTOUT}
60124f8bdc1927b7bb28d8bb4fad7bbdd93811c9vboxsyncstatic DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync /* Last Valid Index */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlowFunc(("LVI[%d] <- %#x\n", GET_BM(index), u32));
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsync /* Control Register */
case PI_SR:
case PO_SR:
case MC_SR:
switch (index)
case PI_SR:
case PO_SR:
case MC_SR:
switch (index)
case PI_BDBAR:
case PO_BDBAR:
case MC_BDBAR:
case GLOB_CNT:
case GLOB_STA:
return VINF_SUCCESS;
static DECLCALLBACK(int) ichac97IOPortNAMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
switch (cb)
*pu32 = ~0U;
*pu32 = ~0U;
switch (index)
*pu32 = ~0U;
return VERR_IOM_IOPORT_UNUSED;
return VINF_SUCCESS;
switch (cb)
switch (index)
case AC97_Reset:
case AC97_Powerdown_Ctrl_Stat:
#ifdef USE_MIXER
case AC97_Master_Volume_Mute:
#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
case AC97_PCM_Out_Volume_Mute:
#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
case AC97_Line_In_Volume_Mute:
#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
case AC97_Record_Select:
case AC97_Master_Volume_Mute:
case AC97_PCM_Out_Volume_Mute:
case AC97_Line_In_Volume_Mute:
case AC97_Record_Select:
case AC97_Vendor_ID1:
case AC97_Vendor_ID2:
case AC97_Extended_Audio_ID:
case AC97_PCM_Front_DAC_Rate:
case AC97_MIC_ADC_Rate:
case AC97_PCM_LR_ADC_Rate:
return VINF_SUCCESS;
static DECLCALLBACK(int) ichac97IOPortMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb,
int rc;
if (iRegion == 0)
return rc;
return VINF_SUCCESS;
#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
return VINF_SUCCESS;
static DECLCALLBACK(int) ichac97LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
AssertMsgReturn (uVersion == AC97_SSM_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
#ifdef USE_MIXER
# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
return VINF_SUCCESS;
return NULL;
#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
return VINF_SUCCESS;
#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
if (pDrv)
return rc;
PCIDevSetVendorId (&pThis->PciDev, 0x8086); /* 00 ro - intel. */ Assert(pThis->PciDev.config[0x00] == 0x86); Assert(pThis->PciDev.config[0x01] == 0x80);
PCIDevSetDeviceId (&pThis->PciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */ Assert(pThis->PciDev.config[0x02] == 0x15); Assert(pThis->PciDev.config[0x03] == 0x24);
PCIDevSetCommand (&pThis->PciDev, 0x0000); /* 04 rw,ro - pcicmd. */ Assert(pThis->PciDev.config[0x04] == 0x00); Assert(pThis->PciDev.config[0x05] == 0x00);
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);
PCIDevSetRevisionId (&pThis->PciDev, 0x01); /* 08 ro - rid. */ Assert(pThis->PciDev.config[0x08] == 0x01);
PCIDevSetClassProg (&pThis->PciDev, 0x00); /* 09 ro - pi. */ Assert(pThis->PciDev.config[0x09] == 0x00);
PCIDevSetClassSub (&pThis->PciDev, 0x01); /* 0a ro - scc; 01 == Audio. */ Assert(pThis->PciDev.config[0x0a] == 0x01);
PCIDevSetClassBase (&pThis->PciDev, 0x04); /* 0b ro - bcc; 04 == multimedia. */ Assert(pThis->PciDev.config[0x0b] == 0x04);
PCIDevSetHeaderType (&pThis->PciDev, 0x00); /* 0e ro - headtyp. */ Assert(pThis->PciDev.config[0x0e] == 0x00);
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);
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);
PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x8086); /* 2c ro - intel.) */ Assert(pThis->PciDev.config[0x2c] == 0x86); Assert(pThis->PciDev.config[0x2d] == 0x80);
PCIDevSetSubSystemId (&pThis->PciDev, 0x0000); /* 2e ro. */ Assert(pThis->PciDev.config[0x2e] == 0x00); Assert(pThis->PciDev.config[0x2f] == 0x00);
PCIDevSetInterruptLine (&pThis->PciDev, 0x00); /* 3c rw. */ Assert(pThis->PciDev.config[0x3c] == 0x00);
PCIDevSetInterruptPin (&pThis->PciDev, 0x01); /* 3d ro - INTA#. */ Assert(pThis->PciDev.config[0x3d] == 0x01);
return rc;
return rc;
return rc;
rc = PDMDevHlpSSMRegister(pDevIns, AC97_SSM_VERSION, sizeof(*pThis), ichac97SaveExec, ichac97LoadExec);
return rc;
#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
return rc;
#ifndef VBOX_WITH_PDM_AUDIO_DRIVER
#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
if (!pThis->paDrv[lun]->pConnector->pfnIsInputOK(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmIn))
if (!pThis->paDrv[lun]->pConnector->pfnIsOutputOK(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmOut))
if (!pThis->paDrv[lun]->pConnector->pfnIsInputOK(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmMic))
len += RTStrPrintf(szMissingVoices + len, sizeof(szMissingVoices) - len, len ? ", PCM_out" : "PCM_out");
len += RTStrPrintf(szMissingVoices + len, sizeof(szMissingVoices) - len, len ? ", PCM_mic" : "PCM_mic");
return VINF_SUCCESS;
sizeof(AC97STATE),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,