VirtualBox

Changeset 53830 in vbox


Ignore:
Timestamp:
Jan 15, 2015 3:44:12 PM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
97643
Message:

PDM/Audio: Unified timer work, minor cleanup.

Location:
trunk/src/VBox/Devices/Audio
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp

    r53567 r53830  
    3838static void audioMixBufFreeBuf(PPDMAUDIOMIXBUF pMixBuf);
    3939static inline void audioMixBufPrint(PPDMAUDIOMIXBUF pMixBuf);
    40 static void audioMixBufReset(PPDMAUDIOMIXBUF pMixBuf);
    4140
    4241typedef uint32_t (AUDMIXBUF_FN_CONVFROM) (PPDMAUDIOSAMPLE paDst, const void *pvSrc, size_t cbSrc, uint32_t cSamples);
     
    5150{
    5251    AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
    53     AssertReturn(cSamplesToRead, VERR_INVALID_PARAMETER);
    5452    AssertPtrReturn(ppvSamples, VERR_INVALID_POINTER);
    5553    AssertPtrReturn(pcSamplesRead, VERR_INVALID_POINTER);
    5654
    5755    int rc;
     56
     57    if (!cSamplesToRead)
     58    {
     59        *pcSamplesRead = 0;
     60        return VINF_SUCCESS;
     61    }
    5862
    5963    uint32_t cSamplesRead;
     
    8690 *
    8791 * @param   pMixBuf
    88  * @param   cSamples
     92 * @param   cSamplesToClear
    8993 */
    90 void audioMixBufFinish(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples)
    91 {
    92     LogFlowFunc(("cSamples=%RU32\n", cSamples));
     94void audioMixBufFinish(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToClear)
     95{
     96    LogFlowFunc(("cSamples=%RU32\n", cSamplesToClear));
    9397    LogFlowFunc(("%s: offReadWrite=%RU32, cProcessed=%RU32\n",
    9498                 pMixBuf->pszName, pMixBuf->offReadWrite, pMixBuf->cProcessed));
     
    98102    {
    99103        LogFlowFunc(("\t%s: cMixed=%RU32 -> %RU32\n",
    100                      pIter->pszName, pIter->cMixed, pIter->cMixed - cSamples));
    101 
    102         Assert(pIter->cMixed >= cSamples);
    103         pIter->cMixed -= cSamples;
     104                     pIter->pszName, pIter->cMixed, pIter->cMixed - cSamplesToClear));
     105
     106        Assert(pIter->cMixed >= cSamplesToClear);
     107        pIter->cMixed -= cSamplesToClear;
    104108        pIter->offReadWrite = 0;
    105109    }
    106110
    107     uint32_t cLeft = RT_MIN(cSamples, pMixBuf->cSamples);
     111    uint32_t cLeft = RT_MIN(cSamplesToClear, pMixBuf->cSamples);
    108112    uint32_t offClear;
    109113
     
    149153}
    150154
     155/** @todo Rename this function! Too confusing in combination with audioMixBufFreeBuf(). */
    151156uint32_t audioMixBufFree(PPDMAUDIOMIXBUF pMixBuf)
    152157{
     
    593598
    594599    pMixBuf->offReadWrite = 0;
    595     pMixBuf->cMixed = 0;
    596     pMixBuf->cProcessed = 0;
     600    pMixBuf->cMixed       = 0;
     601    pMixBuf->cProcessed   = 0;
    597602
    598603    /* Prevent division by zero.
     
    841846static inline void audioMixBufPrint(PPDMAUDIOMIXBUF pMixBuf)
    842847{
    843 #ifdef DEBUG
     848#ifdef DEBUG_DISABLED
    844849    PPDMAUDIOMIXBUF pParent = pMixBuf;
    845850    if (pMixBuf->pParent)
     
    10201025}
    10211026
    1022 static void audioMixBufReset(PPDMAUDIOMIXBUF pMixBuf)
     1027void audioMixBufReset(PPDMAUDIOMIXBUF pMixBuf)
    10231028{
    10241029    AssertPtrReturnVoid(pMixBuf);
     
    10271032
    10281033    pMixBuf->offReadWrite = 0;
    1029     pMixBuf->cMixed = 0;
    1030     pMixBuf->cProcessed = 0;
     1034    pMixBuf->cMixed       = 0;
     1035    pMixBuf->cProcessed   = 0;
    10311036
    10321037    RT_BZERO(pMixBuf->pSamples, AUDIOMIXBUF_S2B(pMixBuf, pMixBuf->cSamples));
  • trunk/src/VBox/Devices/Audio/AudioMixBuffer.h

    r53442 r53830  
    5252inline uint32_t audioMixBufBytesToSamples(PPDMAUDIOMIXBUF pMixBuf);
    5353void audioMixBufDestroy(PPDMAUDIOMIXBUF pMixBuf);
    54 void audioMixBufFinish(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples);
     54void audioMixBufFinish(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToClear);
    5555uint32_t audioMixBufFree(PPDMAUDIOMIXBUF pMixBuf);
    5656size_t audioMixBufFreeBytes(PPDMAUDIOMIXBUF pMixBuf);
     
    6666int audioMixBufReadCirc(PPDMAUDIOMIXBUF pMixBuf, void *pvBuf, size_t cbBuf, uint32_t *pcRead);
    6767int audioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, void *pvBuf, size_t cbBuf, uint32_t *pcRead);
     68void audioMixBufReset(PPDMAUDIOMIXBUF pMixBuf);
    6869uint32_t audioMixBufSize(PPDMAUDIOMIXBUF pMixBuf);
    6970size_t audioMixBufSizeBytes(PPDMAUDIOMIXBUF pMixBuf);
  • trunk/src/VBox/Devices/Audio/DevIchAc97.cpp

    r53624 r53830  
    2323
    2424#include <iprt/assert.h>
    25 #include <iprt/mem.h>
    26 #include <iprt/string.h>
    27 #include <iprt/uuid.h>
     25#ifdef IN_RING3
     26# include <iprt/mem.h>
     27# include <iprt/string.h>
     28# include <iprt/uuid.h>
     29#endif
    2830
    2931#include "VBoxDD.h"
     
    3739#endif
    3840
    39 /*
    4041#ifdef LOG_GROUP
    4142 #undef LOG_GROUP
     
    4344#define LOG_GROUP LOG_GROUP_DEV_AUDIO
    4445#include <VBox/log.h>
    45 */
    4646
    4747/*******************************************************************************
     
    212212
    213213#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     214typedef struct AC97INPUTSTREAM
     215{
     216    /** PCM line input stream. */
     217    R3PTRTYPE(PPDMAUDIOGSTSTRMIN)      pStrmIn;
     218    /** Mixer handle for line input stream. */
     219    R3PTRTYPE(PAUDMIXSTREAM)           phStrmIn;
     220} AC97INPUTSTREAM, *PAC97INPUTSTREAM;
     221
     222typedef struct AC97OUTPUTSTREAM
     223{
     224    /** PCM output stream. */
     225    R3PTRTYPE(PPDMAUDIOGSTSTRMOUT)     pStrmOut;
     226} AC97OUTPUTSTREAM, *PAC97OUTPUTSTREAM;
     227
    214228/**
    215229 * Struct for maintaining a host backend driver.
     
    218232typedef struct AC97DRIVER
    219233{
     234    union
     235    {
     236        /** Node for storing this driver in our device driver
     237         *  list of AC97STATE. */
     238        RTLISTNODE                     Node;
     239        struct
     240        {
     241            R3PTRTYPE(void *)          dummy1;
     242            R3PTRTYPE(void *)          dummy2;
     243        } dummy;
     244    };
     245
    220246    /** Pointer to AC97 controller (state). */
    221     PAC97STATE                         pAC97State;
     247    R3PTRTYPE(PAC97STATE)              pAC97State;
    222248    /** Driver flags. */
    223249    PDMAUDIODRVFLAGS                   Flags;
     250    uint32_t                           PaddingFlags;
    224251    /** LUN # to which this driver has been assigned. */
    225252    uint8_t                            uLUN;
     
    227254     *  host backend. */
    228255    R3PTRTYPE(PPDMIAUDIOCONNECTOR)     pConnector;
    229     /** PCM input stream. */
    230     R3PTRTYPE(PPDMAUDIOGSTSTRMIN)      pStrmIn;
    231     /** Mixer handle for input stream. */
    232     R3PTRTYPE(PAUDMIXSTREAM)           phStrmIn;
    233     /** PCM output stream. */
    234     R3PTRTYPE(PPDMAUDIOGSTSTRMOUT)     pStrmOut;
    235     /** PCM microphone input stream. */
    236     R3PTRTYPE(PPDMAUDIOGSTSTRMIN)      pStrmMic;
    237     /** Mixer handle for output stream. */
    238     R3PTRTYPE(PAUDMIXSTREAM)           phStrmMic;
    239 } AC97DRIVER;
    240 /** Pointer to a AC97 driver. */
    241 typedef AC97DRIVER *PAC97DRIVER;
     256    /** Stream for line input. */
     257    AC97INPUTSTREAM                    LineIn;
     258    /** Stream for mic input. */
     259    AC97INPUTSTREAM                    MicIn;
     260    /** Stream for output. */
     261    AC97OUTPUTSTREAM                   Out;
     262    /** Number of samples to play (output), needed
     263     *  for the timer routine. */
     264    uint32_t                           cSamplesLive;
     265} AC97DRIVER, *PAC97DRIVER;
    242266#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    243267
     
    246270    /** The PCI device state. */
    247271    PCIDevice               PciDev;
    248 
    249     /** Audio stuff. */
    250272    /** Global Control (Bus Master Control Register) */
    251273    uint32_t                glob_cnt;
     
    259281    uint8_t                 mixer_data[256];
    260282#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    261     /** Number of active + allocated LUNs. Each
    262      *  LUN has an AC'97 driver assigned. */
    263     uint8_t                 cLUNs;
    264     /** Array of active AC'97 drivers. */
    265     R3PTRTYPE(PAC97DRIVER)  paDrv[32];
     283    /** The emulation timer for handling the attached
     284     *  LUN drivers. */
     285    PTMTIMERR3              pTimer;
     286    /** Timer ticks for handling the LUN drivers. */
     287    uint64_t                uTicks;
     288# ifdef VBOX_WITH_STATISTICS
     289    STAMPROFILE             StatTimer;
     290    STAMCOUNTER             StatBytesRead;
     291    STAMCOUNTER             StatBytesWritten;
     292# endif
     293    /** List of associated LUN drivers. */
     294    RTLISTANCHOR            lstDrv;
    266295    /** The device' software mixer. */
    267296    R3PTRTYPE(PAUDIOMIXER)  pMixer;
     
    289318    /** Base port of the I/O space region. */
    290319    RTIOPORT                IOPortBase[2];
     320    /** Pointer to temporary scratch read/write buffer. */
     321    R3PTRTYPE(uint8_t *)    pvReadWriteBuf;
     322    /** Size of the temporary scratch read/write buffer. */
     323    uint32_t                cbReadWriteBuf;
    291324} AC97STATE;
    292325/** Pointer to the AC97 device state. */
    293326typedef AC97STATE *PAC97STATE;
     327
     328#ifndef VBOX_DEVICE_STRUCT_TESTCASE
    294329
    295330#define ICHAC97STATE_2_DEVINS(a_pAC97)   ((a_pAC97)->pDevIns)
     
    334369
    335370#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    336 static void ichac97OutputCallback(void *pvContext, uint32_t cbFree);
    337 static void ichac97InputCallback(void *pvContext, uint32_t cbAvail);
    338 static void ichac97MicInCallback(void *pvContext, uint32_t cbAvail);
     371static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
     372static int ichac97TransferAudio(PAC97STATE pThis, int index, uint32_t cbElapsed);
    339373#else
    340374static void ichac97OutputCallback(void *pvContext, int cbFree);
     
    429463
    430464#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     465    PAC97DRIVER pDrv;
    431466    switch (bm_index)
    432467    {
    433468        case PI_INDEX:
    434             for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    435                 pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector,
    436                                                            pThis->paDrv[lun]->pStrmIn, RT_BOOL(on));
     469             RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     470                pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
     471                                              pDrv->LineIn.pStrmIn, RT_BOOL(on));
    437472            break;
    438473
    439474        case PO_INDEX:
    440             for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    441                 pThis->paDrv[lun]->pConnector->pfnEnableOut(pThis->paDrv[lun]->pConnector,
    442                                                             pThis->paDrv[lun]->pStrmOut, RT_BOOL(on));
     475            RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     476                pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
     477                                               pDrv->Out.pStrmOut, RT_BOOL(on));
    443478            break;
    444479
    445480        case MC_INDEX:
    446             for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    447                 pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector,
    448                                                            pThis->paDrv[lun]->pStrmMic, RT_BOOL(on));
     481            RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     482                pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
     483                                              pDrv->MicIn.pStrmIn, RT_BOOL(on));
    449484            break;
    450485
     
    514549
    515550#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     551    PAC97DRIVER pDrv;
     552    uint8_t uLUN = 0;
     553
    516554    if (freq)
    517555    {
     
    527565        switch (index)
    528566        {
    529             case PI_INDEX: /* PCM in */
    530                 for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
     567            case PI_INDEX: /* Line input. */
     568            {
     569                RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
    531570                {
    532                     if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] ac97.pi", lun) <= 0)
     571                    if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] ac97.pi", uLUN) <= 0)
    533572                    {
    534573                        rc = VERR_NO_MEMORY;
     
    536575                    }
    537576
    538                     rc = pThis->paDrv[lun]->pConnector->pfnOpenIn(pThis->paDrv[lun]->pConnector,
    539                                                                   pszDesc, PDMAUDIORECSOURCE_LINE_IN,
    540                                                                   ichac97InputCallback, pThis->paDrv[lun] /* pvContext */,
    541                                                                   &streamCfg,
    542                                                                   &pThis->paDrv[lun]->pStrmIn);
    543                     LogFlowFunc(("LUN#%RU8: Opened line input with rc=%Rrc\n", lun, rc));
     577                    rc = pDrv->pConnector->pfnOpenIn(pDrv->pConnector,
     578                                                     pszDesc, PDMAUDIORECSOURCE_LINE_IN,
     579                                                     NULL, pDrv /* pvContext */,
     580                                                     &streamCfg,
     581                                                     &pDrv->LineIn.pStrmIn);
     582                    LogFlowFunc(("LUN#%RU8: Opened line input with rc=%Rrc\n", uLUN, rc));
    544583                    if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
    545584                    {
    546                         audioMixerRemoveStream(pThis->pSinkLineIn, pThis->paDrv[lun]->phStrmIn);
     585                        audioMixerRemoveStream(pThis->pSinkLineIn, pDrv->LineIn.phStrmIn);
    547586                        rc = audioMixerAddStreamIn(pThis->pSinkLineIn,
    548                                                    pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmIn,
     587                                                   pDrv->pConnector, pDrv->LineIn.pStrmIn,
    549588                                                   0 /* uFlags */,
    550                                                    &pThis->paDrv[lun]->phStrmIn);
     589                                                   &pDrv->LineIn.phStrmIn);
    551590                    }
    552591
    553592                    RTStrFree(pszDesc);
     593                    uLUN++;
    554594                }
    555595                break;
    556 
    557             case PO_INDEX: /* PCM out */
    558                 for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
     596            }
     597
     598            case PO_INDEX: /* Output. */
     599            {
     600                RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
    559601                {
    560                     if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] ac97.po", lun) <= 0)
     602                    if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] ac97.po", uLUN) <= 0)
    561603                    {
    562604                        rc = VERR_NO_MEMORY;
     
    564606                    }
    565607
    566                     rc = pThis->paDrv[lun]->pConnector->pfnOpenOut(pThis->paDrv[lun]->pConnector, pszDesc,
    567                                                                    ichac97OutputCallback, pThis->paDrv[lun] /* pvContext */,
    568                                                                    &streamCfg,
    569                                                                    &pThis->paDrv[lun]->pStrmOut);
    570                     LogFlowFunc(("LUN#%RU8: Opened output with rc=%Rrc\n", lun, rc));
     608                    rc = pDrv->pConnector->pfnOpenOut(pDrv->pConnector, pszDesc,
     609                                                      NULL, pDrv /* pvContext */,
     610                                                      &streamCfg,
     611                                                      &pDrv->Out.pStrmOut);
     612                    LogFlowFunc(("LUN#%RU8: Opened output with rc=%Rrc\n", uLUN, rc));
     613
    571614                    RTStrFree(pszDesc);
     615                    uLUN++;
    572616                }
    573617                break;
     618            }
    574619
    575620            case MC_INDEX: /* Mic in */
    576                 for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
     621            {
     622                RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
    577623                {
    578                     if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] ac97.mc", lun) <= 0)
     624                    if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] ac97.mc", uLUN) <= 0)
    579625                    {
    580626                        rc = VERR_NO_MEMORY;
     
    582628                    }
    583629
    584                     rc = pThis->paDrv[lun]->pConnector->pfnOpenIn(pThis->paDrv[lun]->pConnector,
    585                                                                   pszDesc, PDMAUDIORECSOURCE_MIC,
    586                                                                   ichac97MicInCallback, pThis->paDrv[lun] /* pvContext */,
    587                                                                   &streamCfg,
    588                                                                   &pThis->paDrv[lun]->pStrmMic);
    589                     LogFlowFunc(("LUN#%RU8: Opened mic input with rc=%Rrc\n", lun, rc));
     630                    rc = pDrv->pConnector->pfnOpenIn(pDrv->pConnector,
     631                                                     pszDesc, PDMAUDIORECSOURCE_MIC,
     632                                                     NULL, pDrv /* pvContext */,
     633                                                     &streamCfg,
     634                                                     &pDrv->MicIn.pStrmIn);
     635                    LogFlowFunc(("LUN#%RU8: Opened mic input with rc=%Rrc\n", uLUN, rc));
    590636                    if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
    591637                    {
    592                         audioMixerRemoveStream(pThis->pSinkMicIn, pThis->paDrv[lun]->phStrmMic);
     638                        audioMixerRemoveStream(pThis->pSinkMicIn, pDrv->MicIn.phStrmIn);
    593639                        rc = audioMixerAddStreamIn(pThis->pSinkMicIn,
    594                                                    pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmMic,
     640                                                   pDrv->pConnector, pDrv->MicIn.pStrmIn,
    595641                                                   0 /* uFlags */,
    596                                                    &pThis->paDrv[lun]->phStrmMic);
     642                                                   &pDrv->MicIn.phStrmIn);
    597643                    }
    598644
    599645                    RTStrFree(pszDesc);
     646                    uLUN++;
    600647                }
    601648                break;
     649            }
    602650
    603651            default:
    604652                AssertMsgFailed(("Unsupported index %d\n", index));
     653                rc = VERR_NOT_SUPPORTED;
    605654                break;
    606655        }
     
    611660        {
    612661            case PI_INDEX:
    613                 for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
     662            {
     663                RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
    614664                {
    615                     pThis->paDrv[lun]->pConnector->pfnCloseIn(pThis->paDrv[lun]->pConnector,
    616                                                               pThis->paDrv[lun]->pStrmIn);
    617                     audioMixerRemoveStream(pThis->pSinkLineIn,
    618                                            pThis->paDrv[lun]->phStrmIn);
    619                     pThis->paDrv[lun]->pStrmIn = NULL;
    620                     pThis->paDrv[lun]->phStrmIn = NULL;
     665                    pDrv->pConnector->pfnCloseIn(pDrv->pConnector, pDrv->LineIn.pStrmIn);
     666                    audioMixerRemoveStream(pThis->pSinkLineIn,pDrv->LineIn.phStrmIn);
     667
     668                    pDrv->LineIn.pStrmIn = NULL;
     669                    pDrv->LineIn.phStrmIn = NULL;
    621670                }
    622671
    623672                LogFlowFunc(("Closed line input\n"));
    624673                break;
     674            }
    625675
    626676            case PO_INDEX:
    627                 for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
     677            {
     678                RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
    628679                {
    629                     pThis->paDrv[lun]->pConnector->pfnCloseOut(pThis->paDrv[lun]->pConnector,
    630                                                                pThis->paDrv[lun]->pStrmOut);
    631                     pThis->paDrv[lun]->pStrmOut = NULL;
     680                    pDrv->pConnector->pfnCloseOut(pDrv->pConnector, pDrv->Out.pStrmOut);
     681                    pDrv->Out.pStrmOut = NULL;
    632682                }
    633683
    634684                LogFlowFunc(("Closed output\n"));
    635685                break;
     686            }
    636687
    637688            case MC_INDEX:
    638                 for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
     689            {
     690                RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
    639691                {
    640                     pThis->paDrv[lun]->pConnector->pfnCloseIn(pThis->paDrv[lun]->pConnector,
    641                                                               pThis->paDrv[lun]->pStrmMic);
    642                     audioMixerRemoveStream(pThis->pSinkMicIn,
    643                                            pThis->paDrv[lun]->phStrmMic);
    644                     pThis->paDrv[lun]->pStrmMic = NULL;
    645                     pThis->paDrv[lun]->phStrmMic = NULL;
     692                    pDrv->pConnector->pfnCloseIn(pDrv->pConnector, pDrv->MicIn.pStrmIn);
     693                    audioMixerRemoveStream(pThis->pSinkMicIn, pDrv->MicIn.phStrmIn);
     694
     695                    pDrv->MicIn.pStrmIn  = NULL;
     696                    pDrv->MicIn.phStrmIn = NULL;
    646697                }
    647698
    648                 LogFlowFunc(("Closed mic input\n"));
     699                LogFlowFunc(("Closed microphone input\n"));
    649700                break;
     701            }
    650702
    651703            default:
     
    738790
    739791#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    740     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    741         pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector,
    742                                                    pThis->paDrv[lun]->pStrmIn, fEnable);
     792    PAC97DRIVER pDrv;
     793    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     794        pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, fEnable);
    743795#else
    744796    AUD_set_active_in(pThis->voice_pi, active[PI_INDEX]);
     
    752804
    753805#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    754     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    755         pThis->paDrv[lun]->pConnector->pfnEnableOut(pThis->paDrv[lun]->pConnector,
    756                                                     pThis->paDrv[lun]->pStrmOut, fEnable);
     806    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     807        pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, fEnable);
    757808#else
    758809    AUD_set_active_out(pThis->voice_po, active[PO_INDEX]);
     
    766817
    767818#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    768     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    769         pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector,
    770                                                    pThis->paDrv[lun]->pStrmMic, fEnable);
     819    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     820        pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, fEnable);
    771821#else
    772822     AUD_set_active_in(pThis->voice_mc, active[MC_INDEX]);
     
    788838    lvol = 255 * lvol / VOL_MASK;
    789839
     840#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     841    PAC97DRIVER pDrv;
     842#endif
     843
    790844#ifdef SOFT_VOLUME
    791845    if (index == AC97_Master_Volume_Mute)
    792846    {
    793847# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    794         for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    795         {
    796             pThis->paDrv[lun]->pConnector->pfnIsSetOutVolume(pThis->paDrv[lun]->pConnector,
    797                                                              pThis->paDrv[lun]->pStrmOut,
    798                                                              RT_BOOL(mute), lvol, rvol);
    799         }
     848        RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     849            pDrv->pConnector->pfnIsSetOutVolume(pDrv->pConnector, pDrv->Out.pStrmOut, RT_BOOL(mute), lvol, rvol);
    800850# else
    801851        AUD_set_volume_out(pThis->voice_po, mute, lvol, rvol);
     
    805855    {
    806856# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    807         for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    808         {
    809             /** @todo In SetVolume no passing audmixerctl_in as its not used in DrvAudio.c */
    810             pThis->paDrv[lun]->pConnector->pfnSetVolume(pThis->paDrv[lun]->pConnector,
    811                                                         RT_BOOL(mute), lvol, rvol);
     857        RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     858        {
     859            /** @todo In SetVolume no passing audmixerctl_in as its not used in DrvAudio.cpp. */
     860            pDrv->pConnector->pfnSetVolume(pDrv->pConnector, RT_BOOL(mute), lvol, rvol);
    812861        }
    813862# else
     
    817866#else /* !SOFT_VOLUME */
    818867# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    819     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    820         pThis->paDrv[lun]->pConnector->pfnSetVolume(pThis->paDrv[lun]->pConnector,
    821                                                     RT_BOOL(mute), lvol, rvol);
     868    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     869        pDrv->pConnector->pfnSetVolume(pDrv->pConnector, RT_BOOL(mute), lvol, rvol);
    822870# else
    823871    AUD_set_volume(mt, &mute, &lvol, &rvol);
     
    901949
    902950#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    903     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    904     {
    905         pThis->paDrv[lun]->phStrmIn = NULL;
    906         pThis->paDrv[lun]->phStrmMic = NULL;
     951    PAC97DRIVER pDrv;
     952
     953    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     954    {
     955        pDrv->LineIn.phStrmIn = NULL;
     956        pDrv->MicIn.phStrmIn  = NULL;
    907957    }
    908958
     
    9921042}
    9931043
    994 static int ichac97WriteAudio(PAC97STATE pThis, PAC97BMREG pReg, int max, int *stop)
     1044static int ichac97WriteAudio(PAC97STATE pThis, PAC97BMREG pReg, uint32_t cbMax, uint32_t *pcbWritten)
    9951045{
    9961046    PPDMDEVINS  pDevIns = ICHAC97STATE_2_DEVINS(pThis);
    9971047
    998     uint8_t     tmpbuf[_4K];
    999     uint32_t    addr = pReg->bd.addr;
    1000     uint32_t    written = 0;
    1001     uint32_t    to_copy = 0;
    1002 
    1003     uint32_t temp = RT_MIN((uint32_t)pReg->picb << 1, (uint32_t)max);
    1004     if (!temp)
    1005     {
    1006         *stop = 1;
    1007         return 0;
    1008     }
     1048    uint32_t    addr           = pReg->bd.addr;
     1049    uint32_t    cbWrittenTotal = 0;
     1050    uint32_t    cbToRead;
     1051
     1052    uint32_t cbToWrite = RT_MIN((uint32_t)(pReg->picb << 1), cbMax);
     1053    if (!cbToWrite)
     1054        return VERR_NO_DATA;
    10091055
    10101056    int rc = VINF_SUCCESS;
    10111057
    1012     while (temp)
    1013     {
    1014         uint32_t copied;
    1015         to_copy = RT_MIN(temp, sizeof(tmpbuf));
    1016         PDMDevHlpPhysRead(pDevIns, addr, tmpbuf, to_copy); /** @todo Check rc? */
     1058    LogFlowFunc(("pReg=%p, cbMax=%RU32\n", pReg, cbMax));
     1059
     1060    while (cbToWrite)
     1061    {
     1062        uint32_t cbWritten;
     1063        uint32_t cbWrittenMin = UINT32_MAX;
     1064
     1065        cbToRead = RT_MIN(cbToWrite, pThis->cbReadWriteBuf);
     1066        PDMDevHlpPhysRead(pDevIns, addr, pThis->pvReadWriteBuf, cbToRead); /** @todo Check rc? */
    10171067
    10181068#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1019 # ifdef DEBUG_LUN
    1020         uint8_t lun = DEBUG_LUN_NUM;
    1021 # else
    10221069        /* Just multiplex the output to the connected backends.
    10231070         * No need to utilize the virtual mixer here (yet). */
    1024         for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    1025         {
    1026 # endif
    1027             rc = pThis->paDrv[lun]->pConnector->pfnWrite(pThis->paDrv[lun]->pConnector,
    1028                                                          pThis->paDrv[lun]->pStrmOut,
    1029                                                          tmpbuf, to_copy, &copied);
    1030             if (RT_FAILURE(rc))
     1071        PAC97DRIVER pDrv;
     1072        RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     1073        {
     1074            int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
     1075                                                 pThis->pvReadWriteBuf, cbToRead, &cbWritten);
     1076            if (RT_FAILURE(rc2))
    10311077                continue;
    1032 # ifndef DEBUG_LUN
    1033         }
    1034 # endif
     1078
     1079            cbWrittenMin = RT_MIN(cbWrittenMin, cbWritten);
     1080            LogFlowFunc(("\tLUN#%RU8: cbWritten=%RU32, cWrittenMin=%RU32\n", pDrv->uLUN, cbWritten, cbWrittenMin));
     1081        }
    10351082#else
    1036         copied = AUD_write(pThis->voice_po, tmpbuf, to_copy);
     1083        cbWrittenMin = AUD_write(pThis->voice_po, pThis->pvReadWriteBuf, cbToRead);
    10371084#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    1038         LogFlowFunc(("to_copy=%RU32, copied=%RU32, temp=%RU32, temp_left=%RU32\n",
    1039                      to_copy, copied, temp, temp - copied));
    1040 
    1041         if (!copied)
    1042         {
    1043             *stop = 1;
     1085        LogFlowFunc(("\tcbToRead=%RU32, cbWrittenMin=%RU32, cbToWrite=%RU32, cbLeft=%RU32\n",
     1086                     cbToRead, cbWrittenMin, cbToWrite, cbToWrite - cbWrittenMin));
     1087
     1088        if (!cbWrittenMin)
     1089        {
     1090            rc = VERR_NO_DATA;
    10441091            break;
    10451092        }
    1046         temp    -= copied;
    1047         addr    += copied;
    1048         written += copied;
    1049     }
    1050 
    1051     if (!temp)
    1052     {
    1053         if (to_copy < 4)
    1054         {
    1055             LogFlowFunc(("whoops\n"));
    1056             pThis->last_samp = 0;
    1057         }
    1058         else
    1059             pThis->last_samp = *(uint32_t *)&tmpbuf[to_copy - 4];
     1093
     1094        Assert(cbWrittenMin != UINT32_MAX);
     1095        Assert(cbToWrite >= cbWrittenMin);
     1096        cbToWrite      -= cbWrittenMin;
     1097        addr           += cbWrittenMin;
     1098        cbWrittenTotal += cbWrittenMin;
    10601099    }
    10611100
    10621101    pReg->bd.addr = addr;
    10631102
    1064     LogFlowFunc(("written=%RU32\n", written));
    1065     return written;
    1066 }
    1067 
    1068 static void ichac97WriteBUP(PAC97STATE pThis, int elapsed)
     1103    if (RT_SUCCESS(rc))
     1104    {
     1105        if (!cbToWrite) /* All data written? */
     1106        {
     1107            if (cbToRead < 4)
     1108            {
     1109                AssertMsgFailed(("Unable to save last written sample, cbToRead < 4 (is %RU32)\n", cbToRead));
     1110                pThis->last_samp = 0;
     1111            }
     1112            else
     1113                pThis->last_samp = *(uint32_t *)&pThis->pvReadWriteBuf[cbToRead - 4];
     1114        }
     1115    }
     1116
     1117    if (RT_SUCCESS(rc))
     1118    {
     1119        if (pcbWritten)
     1120            *pcbWritten = cbWrittenTotal;
     1121    }
     1122
     1123    LogFlowFunc(("cbWrittenTotal=%RU32, rc=%Rrc\n", cbWrittenTotal, rc));
     1124    return rc;
     1125}
     1126
     1127static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
    10691128{
    10701129    if (!(pThis->bup_flag & BUP_SET))
     
    10831142    }
    10841143
    1085     int written = 0;
    1086 
    1087     while (elapsed)
    1088     {
    1089         unsigned int temp = RT_MIN((unsigned int)elapsed, sizeof(pThis->silence));
    1090         uint32_t copied;
    1091         while (temp)
     1144    while (cbElapsed)
     1145    {
     1146        uint32_t cbWrittenMin = UINT32_MAX;
     1147
     1148        uint32_t cbToWrite = RT_MIN(cbElapsed, (uint32_t)sizeof(pThis->silence));
     1149        while (cbToWrite)
    10921150        {
    10931151#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1094 # ifdef DEBUG_LUN
    1095             uint8_t lun = DEBUG_LUN_NUM;
    1096 # else
    1097             for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
     1152            PAC97DRIVER pDrv;
     1153            uint32_t cbWritten;
     1154            RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
    10981155            {
    1099 # endif
    1100                 int rc2 = pThis->paDrv[lun]->pConnector->pfnWrite(pThis->paDrv[lun]->pConnector,
    1101                                                                   pThis->paDrv[lun]->pStrmOut,
    1102                                                                   pThis->silence, temp, &copied);
     1156                int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
     1157                                                     pThis->silence, cbToWrite, &cbWritten);
    11031158                if (RT_FAILURE(rc2))
    11041159                    continue;
    1105 # ifndef DEBUG_LUN
     1160
     1161                cbWrittenMin = RT_MIN(cbWrittenMin, cbWritten);
    11061162            }
    1107 # endif
    11081163#else
    1109             copied = AUD_write(pThis->voice_po, pThis->silence, temp);
     1164            cbWrittenMin = AUD_write(pThis->voice_po, pThis->silence, cbToWrite);
    11101165#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    11111166
    1112             if (!copied)
     1167            if (!cbWrittenMin)
    11131168                return;
    1114             temp    -= copied;
    1115             elapsed -= copied;
    1116             written += copied;
    1117         }
    1118     }
    1119 }
    1120 
    1121 static int ichac97ReadAudio(PAC97STATE pThis, PAC97BMREG pReg, int max, int *stop)
    1122 {
    1123     PPDMDEVINS  pDevIns = ICHAC97STATE_2_DEVINS(pThis);
     1169
     1170            Assert(cbToWrite >= cbWrittenMin);
     1171            cbToWrite -= cbWrittenMin;
     1172            Assert(cbElapsed >= cbWrittenMin);
     1173            cbElapsed -= cbWrittenMin;
     1174        }
     1175    }
     1176}
     1177
     1178static int ichac97ReadAudio(PAC97STATE pThis, PAC97BMREG pReg, uint32_t cbMax, uint32_t *pcbWritten)
     1179{
     1180    AssertReturn(cbMax, VERR_INVALID_PARAMETER);
     1181
     1182    PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
     1183
     1184    int rc = VINF_SUCCESS;
    11241185
    11251186#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     
    11291190    AssertPtr(pSink);
    11301191
    1131     int rc;
    1132     uint32_t cbRead;
    1133 
    1134     size_t cbMixBuf = max * sizeof(uint8_t);
    1135     Assert(cbMixBuf);
     1192    uint32_t cbRead = 0;
     1193
     1194    size_t cbMixBuf = cbMax;
    11361195    uint32_t cbToRead = RT_MIN(pReg->picb << 1, cbMixBuf);
     1196
     1197    if (!cbToRead)
     1198        return VERR_NO_DATA;
    11371199
    11381200    uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbMixBuf);
     
    11461208            pReg->bd.addr += cbRead;
    11471209        }
    1148         else
    1149             *stop = 1;
    11501210
    11511211        RTMemFree(pvMixBuf);
    11521212    }
    11531213    else
    1154         *stop = 1;
    1155 
    1156     if (*stop)
    1157         cbRead = 0;
    1158 
    1159     return cbRead;
     1214        rc = VERR_NO_MEMORY;
     1215
     1216    if (RT_SUCCESS(rc))
     1217    {
     1218        Assert(cbRead);
     1219        if (pcbWritten)
     1220            *pcbWritten = cbRead;
     1221    }
     1222
     1223    return rc;
    11601224#else
    11611225    uint32_t    addr = pReg->bd.addr;
     
    11661230    SWVoiceIn  *voice = (pReg - pThis->bm_regs) == MC_INDEX ? pThis->voice_mc : pThis->voice_pi;
    11671231
    1168     temp = audio_MIN(temp, (uint32_t)max);
     1232    temp = audio_MIN(temp, (uint32_t)cbMax);
    11691233    if (!temp)
    1170     {
    1171         *stop = 1;
    1172         return 0;
    1173     }
     1234        return VERR_NO_DATA;
    11741235
    11751236    uint8_t tmpbuf[4096];
     
    11811242        if (!acquired)
    11821243        {
    1183             *stop = 1;
     1244            rc = VERR_GENERAL_FAILURE; /* Not worth fixing anymore. */
    11841245            break;
    11851246        }
     
    11911252
    11921253    pReg->bd.addr = addr;
    1193     return nread;
     1254
     1255    if (RT_SUCCESS(rc))
     1256    {
     1257        if (pcbWritten)
     1258            *pcbWritten = nread;
     1259    }
     1260
     1261    return rc;
    11941262#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    11951263}
    11961264
    11971265#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1198 static void ichac97TransferAudio(PAC97DRIVER pDrv, int index, int elapsed)
    1199 #else
    1200 static void ichac97TransferAudio(PAC97STATE pThis, int index, int elapsed)
     1266static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
     1267{
     1268    PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
     1269    AssertPtr(pThis);
     1270
     1271    STAM_PROFILE_START(&pThis->StatTimer, a);
     1272
     1273    int rc = VINF_SUCCESS;
     1274
     1275    uint32_t cbInMax  = 0;
     1276    uint32_t cbOutMin = UINT32_MAX;
     1277
     1278    PAC97DRIVER pDrv;
     1279    uint32_t cbIn, cbOut;
     1280
     1281    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     1282    {
     1283        if (!pDrv->pConnector->pfnIsOutputOK(pDrv->pConnector, pDrv->Out.pStrmOut))
     1284            continue;
     1285
     1286        rc = pDrv->pConnector->pfnQueryData(pDrv->pConnector, /** @todo Rename QueryStatus */
     1287                                            &cbIn, &cbOut, &pDrv->cSamplesLive);
     1288        if (RT_SUCCESS(rc))
     1289        {
     1290            if (cbIn || cbOut)
     1291                LogFlowFunc(("\tLUN#%RU8: cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, cbIn, cbOut));
     1292
     1293            cbInMax  = RT_MAX(cbInMax, cbIn);
     1294            cbOutMin = RT_MIN(cbOutMin, cbOut);
     1295        }
     1296        else
     1297            pDrv->cSamplesLive = 0;
     1298    }
     1299
     1300    /*
     1301     * Playback.
     1302     */
     1303    if (cbOutMin)
     1304    {
     1305        Assert(cbOutMin != UINT32_MAX);
     1306        ichac97TransferAudio(pThis, PO_INDEX, cbOutMin); /** @todo Add rc! */
     1307    }
     1308    else
     1309    {
     1310        RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     1311        {
     1312            if (pDrv->cSamplesLive)
     1313                pDrv->pConnector->pfnPlayOut(pDrv->pConnector);
     1314        }
     1315    }
     1316
     1317    /*
     1318     * Recording.
     1319     */
     1320    if (cbInMax)
     1321        ichac97TransferAudio(pThis, PI_INDEX, cbInMax); /** @todo Add rc! */
     1322
     1323    TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->uTicks);
     1324
     1325    STAM_PROFILE_STOP(&pThis->StatTimer, a);
     1326}
    12011327#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    1202 {
    1203 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1204     PAC97STATE pThis = pDrv->pAC97State;
    1205 
    1206     if (pDrv->uLUN != 0) /* Only LUN 0 can write and read from the device. */
    1207         return;
    1208     /** @todo Fix this limitation by implementing a virtual mixer. */
    1209 #endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
     1328
     1329static int ichac97TransferAudio(PAC97STATE pThis, int index, uint32_t cbElapsed)
     1330{
     1331    LogFlowFunc(("pThis=%p, index=%d, cbElapsed=%RU32\n", pThis, index, cbElapsed));
    12101332
    12111333    PAC97BMREG pReg = &pThis->bm_regs[index];
     
    12171339            {
    12181340                case PO_INDEX:
    1219                     ichac97WriteBUP(pThis, elapsed);
     1341                    ichac97WriteBUP(pThis, cbElapsed);
    12201342                    break;
    12211343
     
    12251347        }
    12261348
    1227         return;
    1228     }
    1229 
    1230     int written = 0;
    1231     int stop = 0;
    1232 
    1233     while ((elapsed >> 1) && !stop)
    1234     {
    1235         int temp;
    1236 
     1349        return VINF_SUCCESS;
     1350    }
     1351
     1352    int rc;
     1353    uint32_t cbWrittenTotal = 0;
     1354
     1355    while ((cbElapsed >> 1))
     1356    {
    12371357        if (!pReg->bd_valid)
    12381358        {
     
    12601380        }
    12611381
     1382        uint32_t cbWritten;
    12621383        switch (index)
    12631384        {
    12641385            case PO_INDEX:
    1265                 temp = ichac97WriteAudio(pThis, pReg, elapsed, &stop);
    1266                 written += temp;
    1267                 elapsed -= temp;
    1268                 Assert((temp & 1) == 0);    /* Else the following shift won't work */
    1269                 pReg->picb -= (temp >> 1);
     1386            {
     1387                rc = ichac97WriteAudio(pThis, pReg, cbElapsed, &cbWritten);
     1388                if (RT_SUCCESS(rc))
     1389                {
     1390                    cbWrittenTotal += cbWritten;
     1391                    cbElapsed      -= cbWritten;
     1392                    Assert((cbWritten & 1) == 0);    /* Else the following shift won't work */
     1393                    pReg->picb     -= (cbWritten >> 1);
     1394                }
    12701395                break;
     1396            }
    12711397
    12721398            case PI_INDEX:
    12731399            case MC_INDEX:
    1274                 temp = ichac97ReadAudio(pThis, pReg, elapsed, &stop);
    1275                 elapsed -= temp;
    1276                 Assert((temp & 1) == 0);    /* Else the following shift won't work */
    1277                 pReg->picb -= (temp >> 1);
     1400            {
     1401                rc = ichac97ReadAudio(pThis, pReg, cbElapsed, &cbWritten);
     1402                if (RT_SUCCESS(rc))
     1403                {
     1404                    cbElapsed  -= cbWritten;
     1405                    Assert((cbWritten & 1) == 0);    /* Else the following shift won't work */
     1406                    pReg->picb -= (cbWritten >> 1);
     1407                }
    12781408                break;
     1409            }
    12791410
    12801411            default:
    1281                 AssertMsgFailed(("Index %d not supported\n", index));
     1412                AssertMsgFailed(("Index %ld not supported\n", index));
    12821413                break;
    12831414        }
    1284         LogFlowFunc(("pReg->picb = %d\n", pReg->picb));
     1415
     1416        LogFlowFunc(("pReg->picb=%RU16, cbWrittenTotal=%RU32\n", pReg->picb, cbWrittenTotal));
    12851417
    12861418        if (!pReg->picb)
     
    12971429                LogFlowFunc(("Underrun civ (%d) == lvi (%d)\n", pReg->civ, pReg->lvi));
    12981430                new_sr |= SR_LVBCI | SR_DCH | SR_CELV;
    1299                 stop = 1;
    13001431                pThis->bup_flag = (pReg->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
     1432
     1433                rc = VERR_NO_DATA;
    13011434            }
    13021435            else
     
    13091442            ichac97UpdateStatus(pThis, pReg, new_sr);
    13101443        }
    1311     }
    1312 }
    1313 
    1314 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1315 static void ichac97InputCallback(void *pvContext, uint32_t cbAvail)
    1316 {
    1317     PAC97DRIVER pThis = (PAC97DRIVER)pvContext;
    1318     ichac97TransferAudio(pThis, PI_INDEX, cbAvail);
    1319 }
    1320 #else
     1444
     1445        if (RT_FAILURE(rc))
     1446        {
     1447            if (rc == VERR_NO_DATA)
     1448                rc = VINF_SUCCESS;
     1449
     1450            break;
     1451        }
     1452    }
     1453
     1454    LogFlowFuncLeaveRC(rc);
     1455    return rc;
     1456}
     1457
     1458#ifndef VBOX_WITH_PDM_AUDIO_DRIVER
    13211459static void ichac97InputCallback(void *pvContext, int cbAvail)
    13221460{
    13231461    ichac97TransferAudio((AC97STATE *)pvContext, PI_INDEX, cbAvail);
    13241462}
    1325 #endif
    1326 
    1327 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1328 static void ichac97MicInCallback(void *pvContext, uint32_t cbAvail)
    1329 {
    1330     PAC97DRIVER pThis = (PAC97DRIVER)pvContext;
    1331     ichac97TransferAudio(pThis, MC_INDEX, cbAvail);
    1332 }
    1333 #else
     1463
    13341464static void ichac97MicInCallback(void *pvContext, int cbAvail)
    13351465{
    13361466    ichac97TransferAudio((AC97STATE *)pvContext, MC_INDEX, cbAvail);
    13371467}
    1338 #endif
    1339 
    1340 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1341 static void ichac97OutputCallback(void *pvContext, uint32_t cbFree)
    1342 {
    1343     PAC97DRIVER pThis = (PAC97DRIVER)pvContext;
    1344     ichac97TransferAudio(pThis, PO_INDEX, cbFree);
    1345 }
    1346 #else
     1468
    13471469static void ichac97OutputCallback(void *pvContext, int cbFree)
    13481470{
     
    18651987}
    18661988
    1867 
     1989#ifdef IN_RING3
    18681990/**
    18691991 * @callback_method_impl{FNSSMDEVSAVEEXEC}
     
    18962018
    18972019#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1898     /* Writing only host backend values here and ignore data for other backends
    1899      * like VRDE and video recording. LUN 0 always is the host backend. */
    1900     if (pThis->cLUNs >= 1)
    1901     {
    1902         PPDMIAUDIOCONNECTOR pCon = pThis->paDrv[0]->pConnector;
     2020    PAC97DRIVER pDrv;
     2021    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     2022    {
     2023        PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
    19032024        AssertPtr(pCon);
    1904         active[PI_INDEX] = pCon->pfnIsActiveIn(pCon,  pThis->paDrv[0]->pStrmIn) ? 1 : 0;
    1905         active[PO_INDEX] = pCon->pfnIsActiveOut(pCon, pThis->paDrv[0]->pStrmOut) ? 1 : 0;
    1906         active[MC_INDEX] = pCon->pfnIsActiveIn(pCon,  pThis->paDrv[0]->pStrmMic) ? 1 : 0;
    1907     }
    1908     else
    1909         RT_ZERO(active);
     2025        active[PI_INDEX] = pCon->pfnIsActiveIn (pCon, pDrv->LineIn.pStrmIn) ? 1 : 0;
     2026        active[PO_INDEX] = pCon->pfnIsActiveOut(pCon, pDrv->Out.pStrmOut)   ? 1 : 0;
     2027        active[MC_INDEX] = pCon->pfnIsActiveIn (pCon, pDrv->MicIn.pStrmIn)  ? 1 : 0;
     2028    }
    19102029#else
    19112030    active[PI_INDEX] = AUD_is_active_in( pThis->voice_pi) ? 1 : 0;
     
    20252144
    20262145#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    2027     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    2028     {
    2029         if (pThis->paDrv[lun])
    2030         {
    2031             RTMemFree(pThis->paDrv[lun]);
    2032             pThis->paDrv[lun] = NULL;
    2033         }
    2034     }
    2035 
    2036     pThis->cLUNs = 0;
     2146    PAC97DRIVER pDrv;
     2147    while (!RTListIsEmpty(&pThis->lstDrv))
     2148    {
     2149        pDrv = RTListGetFirst(&pThis->lstDrv, AC97DRIVER, Node);
     2150
     2151        RTListNodeRemove(&pDrv->Node);
     2152        RTMemFree(pDrv);
     2153    }
    20372154
    20382155    if (pThis->pMixer)
     
    20422159    }
    20432160#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
     2161
     2162    if (pThis->pvReadWriteBuf)
     2163    {
     2164        RTMemFree(pThis->pvReadWriteBuf);
     2165        pThis->pvReadWriteBuf = NULL;
     2166        pThis->cbReadWriteBuf = 0;
     2167    }
    20442168
    20452169    return VINF_SUCCESS;
     
    20982222                pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
    20992223
    2100             LogFunc(("LUN #%u: pCon=%p, drvFlags=0x%x\n",
    2101                      uLUN, pDrv->pConnector, pDrv->Flags));
    2102 
    2103             pThis->paDrv[uLUN] = pDrv;
    2104             pThis->cLUNs++;
     2224            LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
     2225
     2226            /* Attach to driver list. */
     2227            RTListAppend(&pThis->lstDrv, &pDrv->Node);
    21052228        }
    21062229        else
     
    21902313     */
    21912314#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    2192     /* We support 32 LUNs max. This should be enough for now. */
    2193     for (uint8_t lun = 0; lun < 32 ; lun++)
    2194     {
    2195         LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", lun));
    2196         rc = ichac97Attach(pDevIns, lun, PDM_TACH_FLAGS_NOT_HOT_PLUG);
     2315    RTListInit(&pThis->lstDrv);
     2316
     2317    uint8_t uLUN = 0;
     2318    do
     2319    {
     2320        LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
     2321        rc = ichac97Attach(pDevIns, uLUN++, PDM_TACH_FLAGS_NOT_HOT_PLUG);
    21972322        if (RT_FAILURE(rc))
    21982323        {
     
    22012326            break;
    22022327        }
    2203     }
    2204 
    2205     LogRel(("AC97: %RU8 LUN(s) attached\n", pThis->cLUNs));
     2328
     2329    } while (0);
     2330
     2331    LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
    22062332#else
    22072333    rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Audio Driver Port");
     
    22212347
    22222348#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    2223     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    2224     {
    2225         if (!pThis->paDrv[lun]->pConnector->pfnIsInputOK(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmIn))
    2226             LogRel(("AC97: WARNING: Unable to open PCM line input for LUN #%RU32!\n", lun));
    2227         if (!pThis->paDrv[lun]->pConnector->pfnIsOutputOK(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmOut))
    2228             LogRel(("AC97: WARNING: Unable to open PCM output for LUN #%RU32!\n", lun));
    2229         if (!pThis->paDrv[lun]->pConnector->pfnIsInputOK(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmMic))
    2230             LogRel(("AC97: WARNING: Unable to open PCM microphone input for LUN #%RU32!\n", lun));
    2231     }
    2232 
    2233     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    2234     {
    2235         PAC97DRIVER pDrv = pThis->paDrv[lun];
    2236         AssertPtr(pDrv);
    2237 
    2238         /* Only primary drivers are critical for the VM to run. Everything else
    2239          * might not worth showing an own error message box in the GUI. */
     2349    PAC97DRIVER pDrv;
     2350    uLUN = 0;
     2351    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     2352    {
     2353        if (!pDrv->pConnector->pfnIsInputOK(pDrv->pConnector, pDrv->LineIn.pStrmIn))
     2354            LogRel(("AC97: WARNING: Unable to open PCM line input for LUN #%RU32!\n", uLUN));
     2355        if (!pDrv->pConnector->pfnIsOutputOK(pDrv->pConnector, pDrv->Out.pStrmOut))
     2356            LogRel(("AC97: WARNING: Unable to open PCM output for LUN #%RU32!\n", uLUN));
     2357        if (!pDrv->pConnector->pfnIsInputOK(pDrv->pConnector, pDrv->MicIn.pStrmIn))
     2358            LogRel(("AC97: WARNING: Unable to open PCM microphone input for LUN #%RU32!\n", uLUN));
     2359
     2360        uLUN++;
     2361    }
     2362
     2363    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
     2364    {
     2365        /*
     2366         * Only primary drivers are critical for the VM to run. Everything else
     2367         * might not worth showing an own error message box in the GUI.
     2368         */
    22402369        if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
    22412370            continue;
    22422371
    2243         PPDMIAUDIOCONNECTOR pCon = pThis->paDrv[lun]->pConnector;
     2372        PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
    22442373        AssertPtr(pCon);
    2245         if (   !pCon->pfnIsInputOK (pCon, pDrv->pStrmIn)
    2246             && !pCon->pfnIsOutputOK(pCon, pDrv->pStrmOut)
    2247             && !pCon->pfnIsInputOK (pCon, pDrv->pStrmMic))
    2248         {
    2249             LogRel(("AC97: Selecting NULL driver\n"));
     2374        if (   !pCon->pfnIsInputOK (pCon, pDrv->LineIn.pStrmIn)
     2375            && !pCon->pfnIsOutputOK(pCon, pDrv->Out.pStrmOut)
     2376            && !pCon->pfnIsInputOK (pCon, pDrv->MicIn.pStrmIn))
     2377        {
     2378            LogRel(("AC97: Falling back to NULL driver\n"));
    22502379
    22512380            /* Was not able initialize *any* stream.
    22522381             * Select the NULL audio driver instead. */
    2253             pCon->pfnCloseIn (pCon, pDrv->pStrmIn);
    2254             pCon->pfnCloseOut(pCon, pDrv->pStrmOut);
    2255             pCon->pfnCloseIn (pCon, pDrv->pStrmMic);
    2256 
    2257             pDrv->pStrmOut = NULL;
    2258             pDrv->pStrmIn = NULL;
    2259             pDrv->pStrmMic = NULL;
     2382            pCon->pfnCloseIn (pCon, pDrv->LineIn.pStrmIn);
     2383            pCon->pfnCloseOut(pCon, pDrv->Out.pStrmOut);
     2384            pCon->pfnCloseIn (pCon, pDrv->MicIn.pStrmIn);
     2385
     2386            pDrv->Out.pStrmOut = NULL;
     2387            pDrv->LineIn.pStrmIn = NULL;
     2388            pDrv->MicIn.pStrmIn = NULL;
    22602389
    22612390            pCon->pfnInitNull(pCon);
     
    22662395                   "with the consequence that no sound is audible"));
    22672396        }
    2268         else if (   !pCon->pfnIsInputOK (pCon, pDrv->pStrmIn)
    2269                  || !pCon->pfnIsOutputOK(pCon, pDrv->pStrmOut)
    2270                  || !pCon->pfnIsInputOK (pCon, pDrv->pStrmMic))
    2271         {
    2272             char   szMissingStreams[128];
     2397        else if (   !pCon->pfnIsInputOK (pCon, pDrv->LineIn.pStrmIn)
     2398                 || !pCon->pfnIsOutputOK(pCon, pDrv->Out.pStrmOut)
     2399                 || !pCon->pfnIsInputOK (pCon, pDrv->MicIn.pStrmIn))
     2400        {
     2401            char   szMissingStreams[255];
    22732402            size_t len = 0;
    2274             if (!pCon->pfnIsInputOK (pCon, pDrv->pStrmIn))
     2403            if (!pCon->pfnIsInputOK (pCon, pDrv->LineIn.pStrmIn))
    22752404                len = RTStrPrintf(szMissingStreams,
    22762405                                  sizeof(szMissingStreams), "PCM Input");
    2277             if (!pCon->pfnIsOutputOK(pCon, pDrv->pStrmOut))
     2406            if (!pCon->pfnIsOutputOK(pCon, pDrv->Out.pStrmOut))
    22782407                len += RTStrPrintf(szMissingStreams + len,
    22792408                                   sizeof(szMissingStreams) - len, len ? ", PCM Output" : "PCM Output");
    2280             if (!pCon->pfnIsInputOK (pCon, pDrv->pStrmMic))
     2409            if (!pCon->pfnIsInputOK (pCon, pDrv->MicIn.pStrmIn))
    22812410                len += RTStrPrintf(szMissingStreams + len,
    2282                                    sizeof(szMissingStreams) - len, len ? ", PCM Mic" : "PCM Mic");
     2411                                   sizeof(szMissingStreams) - len, len ? ", PCM Microphone" : "PCM Microphone");
    22832412
    22842413            PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
     
    23352464    }
    23362465#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
     2466
     2467    if (RT_SUCCESS(rc))
     2468    {
     2469        pThis->cbReadWriteBuf = _4K; /** @todo Make this configurable. */
     2470        pThis->pvReadWriteBuf = (uint8_t *)RTMemAlloc(pThis->cbReadWriteBuf);
     2471        if (!pThis->pvReadWriteBuf)
     2472            rc = VERR_NO_MEMORY;
     2473    }
     2474
     2475#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     2476    if (RT_SUCCESS(rc))
     2477    {
     2478        /* Start the emulation timer. */
     2479        rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ichac97Timer, pThis,
     2480                                    TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchAc97", &pThis->pTimer);
     2481        AssertRCReturn(rc, rc);
     2482
     2483        if (RT_SUCCESS(rc))
     2484        {
     2485            pThis->uTicks = PDMDevHlpTMTimeVirtGetFreq(pDevIns) / 200; /** Hz. @todo Make this configurable! */
     2486            if (pThis->uTicks < 100)
     2487                pThis->uTicks = 100;
     2488            LogFunc(("Timer ticks=%RU64\n", pThis->uTicks));
     2489
     2490            /* Fire off timer. */
     2491            TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->uTicks);
     2492        }
     2493    }
     2494
     2495# ifdef VBOX_WITH_STATISTICS
     2496    if (RT_SUCCESS(rc))
     2497    {
     2498        /*
     2499         * Register statistics.
     2500         */
     2501        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer,            STAMTYPE_PROFILE, "/Devices/AC97/Timer",             STAMUNIT_TICKS_PER_CALL, "Profiling hdaTimer.");
     2502        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead,        STAMTYPE_COUNTER, "/Devices/AC97/BytesRead"   ,      STAMUNIT_BYTES,          "Bytes read from AC97 emulation.");
     2503        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten,     STAMTYPE_COUNTER, "/Devices/AC97/BytesWritten",      STAMUNIT_BYTES,          "Bytes written to AC97 emulation.");
     2504    }
     2505# endif
     2506
     2507#endif
    23372508
    23382509    return VINF_SUCCESS;
     
    23932564    PDM_DEVREG_VERSION
    23942565};
     2566
     2567#endif /* !IN_RING3 */
     2568#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
     2569
  • trunk/src/VBox/Devices/Audio/DevIchHda.cpp

    r53624 r53830  
    5858
    5959#ifdef DEBUG
    60 #define DEBUG_LUN
     60//#define DEBUG_LUN
    6161# ifdef DEBUG_LUN
    6262#  define DEBUG_LUN_NUM 0
     
    562562
    563563#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     564typedef struct HDAINPUTSTREAM
     565{
     566    /** PCM line input stream. */
     567    R3PTRTYPE(PPDMAUDIOGSTSTRMIN)      pStrmIn;
     568    /** Mixer handle for line input stream. */
     569    R3PTRTYPE(PAUDMIXSTREAM)           phStrmIn;
     570} HDAINPUTSTREAM, *PHDAINPUTSTREAM;
     571
     572typedef struct HDAOUTPUTSTREAM
     573{
     574    /** PCM output stream. */
     575    R3PTRTYPE(PPDMAUDIOGSTSTRMOUT)     pStrmOut;
     576} HDAOUTPUTSTREAM, *PHDAOUTPUTSTREAM;
     577
    564578/**
    565579 * Struct for maintaining a host backend driver.
     
    567581 * HDA codec. The HDA controller does the actual multiplexing
    568582 * of HDA codec data to various host backend drivers then.
     583 *
     584 * This HDA device uses a timer in order to synchronize all
     585 * read/write accesses across all attached LUNs / backends.
    569586 */
    570587typedef struct HDADRIVER
    571588{
    572     RTLISTNODE                         Node;
     589    union
     590    {
     591        /** Node for storing this driver in our device driver
     592         *  list of HDASTATE. */
     593        RTLISTNODE                     Node;
     594        struct
     595        {
     596            R3PTRTYPE(void *)          dummy1;
     597            R3PTRTYPE(void *)          dummy2;
     598        } dummy;
     599    };
     600
    573601    /** Pointer to HDA controller (state). */
    574     PHDASTATE                          pHDAState;
     602    R3PTRTYPE(PHDASTATE)               pHDAState;
    575603    /** Driver flags. */
    576604    PDMAUDIODRVFLAGS                   Flags;
     605    uint8_t                            u32Padding0[3];
    577606    /** LUN to which this driver has been assigned. */
    578607    uint8_t                            uLUN;
     
    580609     *  host backend. */
    581610    R3PTRTYPE(PPDMIAUDIOCONNECTOR)     pConnector;
    582     /** PCM line input stream. */
    583     R3PTRTYPE(PPDMAUDIOGSTSTRMIN)      pStrmIn;
    584     /** Mixer handle for line input stream. */
    585     R3PTRTYPE(PAUDMIXSTREAM)           phStrmIn;
    586     /** PCM microphone input stream. */
    587     R3PTRTYPE(PPDMAUDIOGSTSTRMIN)      pStrmMic;
    588     /** Mixer handle for microphone input stream. */
    589     R3PTRTYPE(PAUDMIXSTREAM)           phStrmMic;
    590     /** PCM output stream. */
    591     R3PTRTYPE(PPDMAUDIOGSTSTRMOUT)     pGstStrmOut;
     611    /** Stream for line input. */
     612    HDAINPUTSTREAM                     LineIn;
     613    /** Stream for mic input. */
     614    HDAINPUTSTREAM                     MicIn;
     615    /** Stream for output. */
     616    HDAOUTPUTSTREAM                    Out;
     617    /** Number of samples to play (output), needed
     618     *  for the timer routine. */
     619    uint32_t                           cSamplesLive;
    592620} HDADRIVER, *PHDADRIVER;
    593621#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
     
    639667    bool                               fRCEnabled;
    640668#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    641     /** Number of active + allocated LUNs. Each
    642      *  LUN has a HDA driver assigned. */
    643     uint8_t                            cLUNs;
    644     uint8_t                            au8PaddingLUNs[4];
    645     /** The HDA codec to use. */
     669    /** The emulation timer for handling the attached
     670     *  LUN drivers. */
     671    PTMTIMERR3                         pTimer;
     672    /** Timer ticks for handling the LUN drivers. */
     673    uint64_t                           uTicks;
     674# ifdef VBOX_WITH_STATISTICS
     675    STAMPROFILE                        StatTimer;
     676    STAMCOUNTER                        StatBytesRead;
     677    STAMCOUNTER                        StatBytesWritten;
     678# endif
     679    /** Pointer to HDA codec to use. */
    646680    R3PTRTYPE(PHDACODEC)               pCodec;
    647     /** Array of active HDA drivers. */
    648     R3PTRTYPE(PHDADRIVER)              paDrv[32];
     681    union
     682    {
     683        /** List of associated LUN drivers. */
     684        RTLISTANCHOR                   lstDrv;
     685        struct
     686        {
     687            R3PTRTYPE(void *)          dummy1;
     688            R3PTRTYPE(void *)          dummy2;
     689        } dummy;
     690    };
    649691    /** The device' software mixer. */
    650692    R3PTRTYPE(PAUDIOMIXER)             pMixer;
    651     /** Audio sink for line input. */
     693    /** Audio mixer sink for line input. */
    652694    R3PTRTYPE(PAUDMIXSINK)             pSinkLineIn;
    653     /** Audio sink for microphone input. */
     695    /** Audio mixer sink for microphone input. */
    654696    R3PTRTYPE(PAUDMIXSINK)             pSinkMicIn;
    655 #else
    656     R3PTRTYPE(PPDMIAUDIOCONNECTOR)     pDrv;
     697#else /* !VBOX_WITH_PDM_AUDIO_DRIVER */
    657698    /** The HDA codec to use. */
    658699    R3PTRTYPE(PHDACODEC)               pCodec;
     
    662703    uint8_t                            u8Counter;
    663704#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    664     uint8_t                            au8Padding[4];
     705    uint8_t                            au8Padding[7];
    665706#else
    666707    uint8_t                            au8Padding[7];
     
    718759
    719760#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    720 static void hdaTransfer(PHDADRIVER pDrv, ENMSOUNDSOURCE enmSrc, uint32_t cbAvail);
     761static DECLCALLBACK(void) hdaTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
     762static int hdaTransfer(PHDASTATE pThis, ENMSOUNDSOURCE enmSrc, uint32_t cbAvail);
    721763#else
    722 static void hdaTransfer(PHDACODEC pCodec, ENMSOUNDSOURCE enmSource, int cbAvail);
     764static int hdaTransfer(PHDACODEC pCodec, ENMSOUNDSOURCE enmSource, int cbAvail);
    723765#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    724766
     
    15291571        {
    15301572            Assert((!fReset && !fInReset));
     1573
     1574            PHDADRIVER pDrv;
    15311575            switch (iReg)
    15321576            {
    15331577                case HDA_REG_SD0CTL:
    1534 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1535                     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    1536                         pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector,
    1537                                                                    pThis->paDrv[lun]->pStrmIn, fRun);
    1538 #else
     1578# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     1579                    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     1580                        pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
     1581                                                      pDrv->LineIn.pStrmIn, fRun);
     1582# else
    15391583                    AUD_set_active_in(pThis->pCodec->SwVoiceIn, fRun);
    1540 #endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
     1584# endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    15411585                    break;
    1542 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1543 # ifdef VBOX_WITH_HDA_MIC_IN
     1586# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     1587#  ifdef VBOX_WITH_HDA_MIC_IN
    15441588                case HDA_REG_SD2CTL:
    1545                     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    1546                         pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector,
    1547                                                                    pThis->paDrv[lun]->pStrmMic, fRun);
    1548 # endif
    1549 #endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
     1589                    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     1590                        pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
     1591                                                      pDrv->MicIn.pStrmIn, fRun);
     1592#  endif
     1593# endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    15501594                    break;
    15511595                case HDA_REG_SD4CTL:
    1552 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1553                     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    1554                         pThis->paDrv[lun]->pConnector->pfnEnableOut(pThis->paDrv[lun]->pConnector,
    1555                                                                     pThis->paDrv[lun]->pGstStrmOut, fRun);
    1556 #else
     1596# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     1597                    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     1598                        pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
     1599                                                       pDrv->Out.pStrmOut, fRun);
     1600# else
    15571601                    AUD_set_active_out(pThis->pCodec->SwVoiceOut, fRun);
    1558 #endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
     1602# endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    15591603                    break;
    15601604                default:
     
    15651609#else /* !IN_RING3 */
    15661610        return VINF_IOM_R3_MMIO_WRITE;
    1567 #endif
     1611#endif /* IN_RING3 */
    15681612    }
    15691613
     
    17681812        return rc;
    17691813
     1814    PHDADRIVER pDrv;
    17701815    switch (iReg)
    17711816    {
    17721817        case HDA_REG_SD0FMT:
    1773             for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
     1818            RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
    17741819                rc = hdaCodecOpenStream(pThis->pCodec, PI_INDEX, &as);
    17751820            break;
     
    17771822# ifdef VBOX_WITH_HDA_MIC_IN
    17781823        case HDA_REG_SD2FMT:
    1779             for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
     1824            RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
    17801825                rc = hdaCodecOpenStream(pThis->pCodec, MC_INDEX, &as);
    17811826            break;
     
    18501895        HDA_REG(pThis, IRS) = HDA_REG_FIELD_FLAG_MASK(IRS, ICB);  /* busy */
    18511896        LogFunc(("IC:%x\n", cmd));
    1852 # if 0
    1853         for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    1854         {
    1855             rc = pThis->pCodec[lun]->pfnLookup(pThis->pCodec[lun],
    1856                                                HDA_CODEC_CMD(cmd, lun),
    1857                                                &pfn);
    1858             if (RT_SUCCESS(rc))
    1859             {
    1860                 AssertPtr(pfn);
    1861                 rc = pfn(pThis->pCodec[lun],
    1862                          HDA_CODEC_CMD(cmd, lun), &resp);
    1863                 if (RT_FAILURE(rc))
    1864                     break;
    1865             }
    1866         }
    1867 # else
     1897
    18681898        rc = pThis->pCodec->pfnLookup(pThis->pCodec,
    18691899                                      HDA_CODEC_CMD(cmd, 0 /* LUN */),
     
    18731903        rc = pfn(pThis->pCodec,
    18741904                 HDA_CODEC_CMD(cmd, 0 /* LUN */), &resp);
    1875 # endif
    1876 
    18771905        if (RT_FAILURE(rc))
    18781906            AssertRCReturn(rc, rc);
     1907
    18791908        HDA_REG(pThis, IR) = (uint32_t)resp;
    18801909        LogFunc(("IR:%x\n", HDA_REG(pThis, IR)));
     
    20082037                                                      uint32_t u32SoundBackendBufferBytesAvail, uint32_t u32CblLimit)
    20092038{
    2010     uint32_t cb2Copy;
    20112039    /*
    20122040     * Number of bytes depends on the current position in buffer (u32BdleCviLen-u32BdleCviPos)
    20132041     */
    20142042    Assert((pBdle->u32BdleCviLen >= pBdle->u32BdleCviPos)); /* sanity */
    2015     cb2Copy = pBdle->u32BdleCviLen - pBdle->u32BdleCviPos;
     2043    uint32_t cb2Copy = pBdle->u32BdleCviLen - pBdle->u32BdleCviPos;
    20162044    /*
    20172045     * we may increase the counter in range of [0, FIFOS + 1]
     
    21692197 *       but "reports bytes" when all conditions are met (FIFOW).
    21702198 */
    2171 static uint32_t hdaReadAudio(PHDASTATE pThis, PAUDMIXSINK pSink, PHDABDLEDESC pBdle,
     2199static uint32_t hdaReadAudio(PHDASTATE pThis, PAUDMIXSINK pSink,
    21722200                             PHDASTREAMTRANSFERDESC pStreamDesc,
    2173                              uint32_t *pu32Avail, bool *fStop, uint32_t u32CblLimit)
    2174 {
     2201                             uint32_t u32CblLimit, uint32_t *pcbAvail, uint32_t *pcbRead)
     2202{
     2203    PHDABDLEDESC pBdle = &pThis->StInBdle; /** @todo Add support for mic in. */
     2204
     2205    int rc;
    21752206    uint32_t cbTransferred = 0;
    21762207
    21772208    LogFlowFunc(("CVI(pos:%d, len:%d)\n", pBdle->u32BdleCviPos, pBdle->u32BdleCviLen));
    21782209
    2179     uint32_t cb2Copy = hdaCalculateTransferBufferLength(pBdle, pStreamDesc, *pu32Avail, u32CblLimit);
     2210    uint32_t cb2Copy = hdaCalculateTransferBufferLength(pBdle, pStreamDesc, *pcbAvail, u32CblLimit);
    21802211    if (!cb2Copy)
    21812212    {
    21822213        /* If we enter here we can't report "unreported bits". */
    2183         *fStop = true;
     2214        rc = VERR_NO_DATA;
    21842215    }
    21852216    else
    21862217    {
    21872218        uint32_t cbRead = 0;
    2188         int rc = audioMixerProcessSinkIn(pSink, pBdle->au8HdaBuffer, cb2Copy, &cbRead);
     2219        rc = audioMixerProcessSinkIn(pSink, pBdle->au8HdaBuffer, cb2Copy, &cbRead);
    21892220        if (RT_SUCCESS(rc))
    21902221        {
     2222            Assert(cbRead);
     2223
    21912224            /*
    21922225             * Write the HDA DMA buffer.
     
    21972230
    21982231            /* Don't see any reason why cb2Copy would differ from cbRead. */
    2199             Assert((cbRead == cb2Copy && (*pu32Avail) >= cb2Copy)); /* sanity */
     2232            Assert((cbRead == cb2Copy && (*pcbAvail) >= cb2Copy)); /* sanity */
    22002233
    22012234            if (pBdle->cbUnderFifoW + cbRead > hdaFifoWToSz(pThis, 0))
    2202                 hdaBackendReadTransferReported(pBdle, cb2Copy, cbRead, &cbTransferred, pu32Avail);
     2235                hdaBackendReadTransferReported(pBdle, cb2Copy, cbRead, &cbTransferred, pcbAvail);
    22032236            else
    22042237            {
    2205                 hdaBackendTransferUnreported(pThis, pBdle, pStreamDesc, cbRead, pu32Avail);
    2206                 *fStop = true;
     2238                hdaBackendTransferUnreported(pThis, pBdle, pStreamDesc, cbRead, pcbAvail);
     2239                rc = VERR_NO_DATA;
    22072240            }
    22082241        }
    2209         else
    2210             *fStop = true;
    22112242    }
    22122243
    22132244    Assert((cbTransferred <= (SDFIFOS(pThis, 0) + 1)));
    2214     LogFunc(("CVI(pos:%RU32, len:%RU32), cbTransferred: %RU32\n",
    2215              pBdle->u32BdleCviPos, pBdle->u32BdleCviLen, cbTransferred));
    2216     return cbTransferred;
     2245    LogFunc(("CVI(pos:%RU32, len:%RU32), cbTransferred=%RU32, rc=%Rrc\n",
     2246             pBdle->u32BdleCviPos, pBdle->u32BdleCviLen, cbTransferred, rc));
     2247
     2248    if (RT_SUCCESS(rc))
     2249        *pcbRead = cbTransferred;
     2250
     2251    return rc;
    22172252}
    22182253#else
     
    22202255{
    22212256    PHDABDLEDESC pBdle = &pThis->StInBdle;
     2257
    22222258    uint32_t cbTransferred = 0;
    22232259    uint32_t cb2Copy = 0;
     
    22352271         * read from backend input line to the last unreported position or at the begining.
    22362272         */
    2237 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    2238         //cbBackendCopy = pThis->pDrv[0]->pfnRead(pThis->pDrv[0], pThis->pCodec[0]->SwVoiceIn, pBdle->au8HdaBuffer, cb2Copy);
    2239         //cbBackendCopy = pThis->pDrv[0]->pfnRead(pThis->pDrv[0], pThis->pCodec[1]->SwVoiceIn, pBdle->au8HdaBuffer, cb2Copy);
    2240 #else
    22412273        cbBackendCopy = AUD_read(pThis->pCodec->SwVoiceIn, pBdle->au8HdaBuffer, cb2Copy);
    2242 #endif
     2274
    22432275        /*
    22442276         * write the HDA DMA buffer
    22452277         */
    2246         PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pBdle->u64BdleCviAddr + pBdle->u32BdleCviPos, pBdle->au8HdaBuffer, cbBackendCopy);
     2278        PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pBdle->u64BdleCviAddr + pBdle->u32BdleCviPos, pBdle->au8HdaBuffer,
     2279                              cbBackendCopy);
     2280        STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbBackendCopy);
    22472281
    22482282        /* Don't see any reason why cb2Copy would differ from cbBackendCopy */
     
    22642298#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    22652299
    2266 static uint32_t hdaWriteAudio(PHDASTATE pThis, PHDASTREAMTRANSFERDESC pStreamDesc, uint32_t *pu32Avail, bool *fStop, uint32_t u32CblLimit)
     2300static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAMTRANSFERDESC pStreamDesc, uint32_t u32CblLimit,
     2301                         uint32_t *pcbAvail, uint32_t *pcbWritten)
    22672302{
    22682303    PHDABDLEDESC pBdle = &pThis->StOutBdle;
     2304
     2305    int rc;
     2306
    22692307    uint32_t cbTransferred = 0;
    2270     uint32_t cbWrittenMax = 0; /* local byte counter, how many bytes copied to backend */
     2308    uint32_t cbWrittenMin = 0; /* local byte counter, how many bytes copied to backend */
    22712309
    22722310    LogFunc(("CVI(cvi:%RU32, pos:%RU32, len:%RU32)\n", pBdle->u32BdleCvi, pBdle->u32BdleCviPos, pBdle->u32BdleCviLen));
    22732311
    22742312    /* Local byte counter (on local buffer). */
    2275     uint32_t cb2Copy = hdaCalculateTransferBufferLength(pBdle, pStreamDesc, *pu32Avail, u32CblLimit);
     2313    uint32_t cb2Copy = hdaCalculateTransferBufferLength(pBdle, pStreamDesc, *pcbAvail, u32CblLimit);
    22762314
    22772315    /*
     
    22802318     */
    22812319    if (!cb2Copy)
    2282         *fStop = true;
     2320    {
     2321        rc = VERR_NO_DATA;
     2322    }
    22832323    else
    22842324    {
     
    22862326                          pBdle->u64BdleCviAddr + pBdle->u32BdleCviPos,
    22872327                          pBdle->au8HdaBuffer + pBdle->cbUnderFifoW, cb2Copy);
     2328        STAM_COUNTER_ADD(&pThis->StatBytesRead, cb2Copy);
    22882329
    22892330        /*
     
    22932334        {
    22942335#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    2295             int rc;
    22962336            uint32_t cbWritten;
    2297 # ifdef DEBUG_LUN
    2298             uint8_t lun = DEBUG_LUN_NUM;
    2299 # else
    2300             for (uint8_t lun = 0; lun < 1; lun++)
     2337            cbWrittenMin = UINT32_MAX;
     2338
     2339            PHDADRIVER pDrv;
     2340            RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
    23012341            {
    2302 # endif
    2303                 rc = pThis->paDrv[lun]->pConnector->pfnWrite(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pGstStrmOut,
    2304                                                              pBdle->au8HdaBuffer, cb2Copy + pBdle->cbUnderFifoW,
    2305                                                              &cbWritten);
    2306 # ifndef DEBUG_LUN
    2307                 if (RT_FAILURE(rc))
    2308                     continue;
    2309 # endif
    2310                 cbWrittenMax = RT_MAX(cbWrittenMax, cbWritten);
    2311 # ifndef DEBUG_LUN
     2342                if (pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut))
     2343                {
     2344                    rc = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
     2345                                                    pBdle->au8HdaBuffer, cb2Copy + pBdle->cbUnderFifoW,
     2346                                                    &cbWritten);
     2347                    if (RT_FAILURE(rc))
     2348                        continue;
     2349                }
     2350                else /* Stream disabled, just assume all was copied. */
     2351                    cbWritten = cb2Copy;
     2352
     2353                cbWrittenMin = RT_MIN(cbWrittenMin, cbWritten);
     2354                LogFlowFunc(("\tLUN#%RU8: cbWritten=%RU32, cWrittenMin=%RU32\n", pDrv->uLUN, cbWritten, cbWrittenMin));
    23122355            }
    2313 # endif
     2356
     2357            if (cbWrittenMin == UINT32_MAX)
     2358                cbWrittenMin = 0;
    23142359#else
    2315             cbWrittenMax = AUD_write (pThis->pCodec->SwVoiceOut, pBdle->au8HdaBuffer, cb2Copy + pBdle->cbUnderFifoW);
     2360            cbWrittenMin = AUD_write (pThis->pCodec->SwVoiceOut, pBdle->au8HdaBuffer, cb2Copy + pBdle->cbUnderFifoW);
    23162361#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    23172362
    2318             hdaBackendWriteTransferReported(pBdle, cb2Copy, cbWrittenMax, &cbTransferred, pu32Avail);
     2363            hdaBackendWriteTransferReported(pBdle, cb2Copy, cbWrittenMin, &cbTransferred, pcbAvail);
    23192364        }
    23202365        else
     
    23222367            /* Not enough bytes to be processed and reported, we'll try our luck next time around. */
    23232368            hdaBackendTransferUnreported(pThis, pBdle, pStreamDesc, cb2Copy, NULL);
    2324             *fStop = true;
     2369            rc = VERR_NO_DATA;
    23252370        }
    23262371    }
    23272372
    23282373    Assert(cbTransferred <= SDFIFOS(pThis, 4) + 1);
    2329     LogFunc(("CVI(pos:%RU32, len:%RU32, cbTransferred:%RU32)\n", pBdle->u32BdleCviPos, pBdle->u32BdleCviLen, cbTransferred));
    2330     return cbTransferred;
     2374    LogFunc(("CVI(pos:%RU32, len:%RU32, cbTransferred:%RU32), rc=%Rrc\n",
     2375             pBdle->u32BdleCviPos, pBdle->u32BdleCviLen, cbTransferred, rc));
     2376
     2377    if (RT_SUCCESS(rc))
     2378        *pcbWritten = cbTransferred;
     2379
     2380    return rc;
    23312381}
    23322382
     
    23822432
    23832433#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    2384 # ifdef VBOX_WITH_HDA_MIC_IN
    2385 static void hdaMicInputCallback(void *pvDrv, uint32_t cbAvail)
    2386 {
    2387     PHDADRIVER pThis = (PHDADRIVER)pvDrv;
    2388     hdaTransfer(pThis, MC_INDEX, cbAvail);
    2389 }
    2390 # endif /* VBOX_WITH_HDA_MIC_IN */
    2391 
    2392 static void hdaLineInputCallback(void *pvDrv, uint32_t cbAvail)
    2393 {
    2394     PHDADRIVER pThis = (PHDADRIVER)pvDrv;
    2395     hdaTransfer(pThis, PI_INDEX, cbAvail);
    2396 }
    2397 
    2398 static void hdaOutputCallback(void *pvDrv, uint32_t cbFree)
    2399 {
    2400     PHDADRIVER pThis = (PHDADRIVER)pvDrv;
    2401     hdaTransfer(pThis, PO_INDEX, cbFree);
    2402 }
    2403 
    24042434static DECLCALLBACK(int) hdaOpenIn(PHDASTATE pThis,
    24052435                                   const char *pszName, PDMAUDIORECSOURCE enmRecSource,
    24062436                                   PPDMAUDIOSTREAMCFG pCfg)
    24072437{
    2408     PDMAUDIOCALLBACK_FN pfnCallback;
    24092438    PAUDMIXSINK pSink;
    24102439
     
    24132442# ifdef VBOX_WITH_HDA_MIC_IN
    24142443        case PDMAUDIORECSOURCE_MIC:
    2415             pfnCallback = hdaMicInputCallback;
    24162444            pSink = pThis->pSinkMicIn;
    24172445            break;
    24182446# endif
    24192447        case PDMAUDIORECSOURCE_LINE_IN:
    2420             pfnCallback = hdaLineInputCallback;
    24212448            pSink = pThis->pSinkLineIn;
    24222449            break;
     
    24292456    char *pszDesc;
    24302457
    2431     Assert(pThis->cLUNs);
    2432     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    2433     {
    2434         if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s", lun, pszName) <= 0)
     2458    PHDADRIVER pDrv;
     2459    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     2460    {
     2461        if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s", pDrv->uLUN, pszName) <= 0)
    24352462        {
    24362463            rc = VERR_NO_MEMORY;
     
    24382465        }
    24392466
    2440         PHDADRIVER pDrv = pThis->paDrv[lun];
    24412467        rc = pDrv->pConnector->pfnOpenIn(pDrv->pConnector,
    24422468                                         pszDesc, enmRecSource,
    2443                                          pfnCallback /* fnCallback */, pDrv /* pvCallback */,
     2469                                         NULL /* fnCallback */, NULL /* pvCallback */,
    24442470                                         pCfg,
    2445                                          &pDrv->pStrmIn);
    2446         LogFlowFunc(("LUN#%RU8: Opened input \"%s\", with rc=%Rrc\n", lun, pszDesc, rc));
     2471                                         &pDrv->LineIn.pStrmIn);
     2472        LogFlowFunc(("LUN#%RU8: Opened input \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
    24472473        if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
    24482474        {
    2449             audioMixerRemoveStream(pSink, pDrv->phStrmIn);
     2475            audioMixerRemoveStream(pSink, pDrv->LineIn.phStrmIn);
    24502476            rc = audioMixerAddStreamIn(pSink,
    2451                                        pDrv->pConnector, pDrv->pStrmIn,
    2452                                        0 /* uFlags */, &pDrv->phStrmIn);
     2477                                       pDrv->pConnector, pDrv->LineIn.pStrmIn,
     2478                                       0 /* uFlags */, &pDrv->LineIn.phStrmIn);
    24532479        }
    24542480
     
    24632489                                    const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
    24642490{
    2465     int rc;
    2466 
    2467     Assert(pThis->cLUNs);
    2468     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    2469     {
    2470         PHDADRIVER pDrv = pThis->paDrv[lun];
    2471         rc = pDrv->pConnector->pfnOpenOut(pDrv->pConnector, pszName,
    2472                                           hdaOutputCallback /* fnCallback */, pDrv /* pvCallback */,
    2473                                           pCfg,
    2474                                           &pDrv->pGstStrmOut);
     2491    int rc = VINF_SUCCESS;
     2492
     2493    PHDADRIVER pDrv;
     2494    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     2495    {
     2496        int rc2 = pDrv->pConnector->pfnOpenOut(pDrv->pConnector, pszName,
     2497                                               NULL /* fnCallback */, pDrv /* pvCallback */,
     2498                                               pCfg,
     2499                                               &pDrv->Out.pStrmOut);
     2500        if (RT_FAILURE(rc2))
     2501        {
     2502            LogFunc(("LUN#%RU8: Opening stream \"%s\" failed, rc=%Rrc\n", pDrv->uLUN, pszName, rc2));
     2503            if (RT_SUCCESS(rc))
     2504                rc = rc2;
     2505            /* Keep going. */
     2506        }
    24752507    }
    24762508
     
    24822514                                      bool fMute, uint8_t uVolLeft, uint8_t uVolRight)
    24832515{
    2484     int rc;
    2485 
    2486     Assert(pThis->cLUNs);
    2487     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    2488     {
    2489         PHDADRIVER pDrv = pThis->paDrv[lun];
    2490         rc = pDrv->pConnector->pfnSetVolume(pDrv->pConnector,
    2491                                             fMute, uVolLeft, uVolRight);
     2516    int rc = VINF_SUCCESS;
     2517
     2518    PHDADRIVER pDrv;
     2519    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     2520    {
     2521        int rc2 = pDrv->pConnector->pfnSetVolume(pDrv->pConnector,
     2522                                                 fMute, uVolLeft, uVolRight);
     2523        if (RT_FAILURE(rc2))
     2524        {
     2525            LogFunc(("Failed for LUN #%RU8, rc=%Rrc\n", pDrv->uLUN, rc2));
     2526            if (RT_SUCCESS(rc))
     2527                rc = rc2;
     2528            /* Keep going. */
     2529        }
    24922530    }
    24932531
     
    24982536
    24992537#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    2500 static DECLCALLBACK(void) hdaTransfer(PHDADRIVER pDrv,
    2501                                       ENMSOUNDSOURCE enmSrc, uint32_t cbAvail)
    2502 {
    2503     AssertPtrReturnVoid(pDrv);
    2504     PHDASTATE pThis = pDrv->pHDAState;
    2505 
    2506     LogFlowFunc(("pDrv=%p (LUN #%RU8), enmSrc=%ld, cbAvail=%RU32\n",
    2507                  pDrv, pDrv->uLUN, enmSrc, cbAvail));
     2538static DECLCALLBACK(void) hdaTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
     2539{
     2540    PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
     2541    AssertPtr(pThis);
     2542
     2543    STAM_PROFILE_START(&pThis->StatTimer, a);
     2544
     2545    int rc = VINF_SUCCESS;
     2546
     2547    uint32_t cbInMax  = 0;
     2548    uint32_t cbOutMin = UINT32_MAX;
     2549
     2550    PHDADRIVER pDrv;
     2551    uint32_t cbIn, cbOut;
     2552#ifdef DEBUG_LUN
     2553    uint8_t uLUN = 0;
     2554#endif
     2555    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     2556    {
     2557        if (!pDrv->pConnector->pfnIsOutputOK(pDrv->pConnector, pDrv->Out.pStrmOut))
     2558            continue;
     2559
     2560        rc = pDrv->pConnector->pfnQueryData(pDrv->pConnector, /** @todo Rename QueryStatus */
     2561                                            &cbIn, &cbOut, &pDrv->cSamplesLive);
     2562        if (RT_SUCCESS(rc))
     2563        {
     2564#ifdef DEBUG_LUN
     2565            LogFlowFunc(("\tLUN#%RU8: cbIn=%RU32, cbOut=%RU32\n", uLUN, cbIn, cbOut));
     2566#endif
     2567            cbInMax  = RT_MAX(cbInMax, cbIn);
     2568            cbOutMin = RT_MIN(cbOutMin, cbOut);
     2569        }
     2570        else
     2571            pDrv->cSamplesLive = 0;
     2572
     2573#ifdef DEBUG_LUN
     2574        uLUN++;
     2575#endif
     2576    }
     2577
     2578    /*
     2579     * Playback.
     2580     */
     2581    if (cbOutMin)
     2582    {
     2583        Assert(cbOutMin != UINT32_MAX);
     2584        hdaTransfer(pThis, PO_INDEX, cbOutMin); /** @todo Add rc! */
     2585    }
     2586    else
     2587    {
     2588        RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     2589        {
     2590            if (pDrv->cSamplesLive)
     2591                pDrv->pConnector->pfnPlayOut(pDrv->pConnector);
     2592        }
     2593    }
     2594
     2595    /*
     2596     * Recording.
     2597     */
     2598    if (cbInMax)
     2599        hdaTransfer(pThis, PI_INDEX, cbInMax); /** @todo Add rc! */
     2600
     2601    TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->uTicks);
     2602
     2603    STAM_PROFILE_STOP(&pThis->StatTimer, a);
     2604}
     2605
     2606static DECLCALLBACK(int) hdaTransfer(PHDASTATE pThis,
     2607                                     ENMSOUNDSOURCE enmSrc, uint32_t cbAvail)
     2608{
     2609    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     2610
     2611    LogFlowFunc(("pThis=%p, cbAvail=%RU32\n", pThis, cbAvail));
    25082612#else
    2509 static DECLCALLBACK(void) hdaTransfer(PHDACODEC pCodec, ENMSOUNDSOURCE enmSrc, int cbAvail)
    2510 {
    2511     AssertPtrReturnVoid(pCodec);
     2613static DECLCALLBACK(int) hdaTransfer(PHDACODEC pCodec, ENMSOUNDSOURCE enmSrc, int cbAvail)
     2614{
     2615    AssertPtrReturnVoid(pCodec, VERR_INVALID_POINTER);
    25122616    PHDASTATE pThis = pCodec->pHDAState;
     2617    AssertPtrReturnVoid(pThis, VERR_INVALID_POINTER);
    25132618#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
     2619    int rc;
     2620
    25142621    uint8_t      u8Strm;
    25152622    PHDABDLEDESC pBdle;
     
    25412648        default:
    25422649            AssertMsgFailed(("Unknown source index %ld\n", enmSrc));
    2543             return;
     2650            return VERR_NOT_SUPPORTED;
    25442651    }
    25452652
     
    25472654    hdaInitTransferDescriptor(pThis, pBdle, u8Strm, &StreamDesc);
    25482655
    2549     bool fStop = false;
    2550     while (cbAvail && !fStop)
     2656    while (cbAvail)
    25512657    {
    25522658        Assert(   (StreamDesc.u32Ctl & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN))
     
    25682674        PAUDMIXSINK pSink;
    25692675#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    2570         uint32_t cb;
     2676        uint32_t cbWritten;
    25712677        switch (enmSrc)
    25722678        {
     
    25742680#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    25752681                pSink = pThis->pSinkLineIn;
    2576                 cb = hdaReadAudio(pThis, pSink, pBdle, &StreamDesc, &cbAvail, &fStop, u32CblLimit);
     2682                rc = hdaReadAudio(pThis, pSink, &StreamDesc, u32CblLimit, &cbAvail, &cbWritten);
    25772683#else
    2578                 cb = hdaReadAudio(pThis, &StreamDesc, (uint32_t *)&cbAvail, &fStop, u32CblLimit);
     2684                rc = hdaReadAudio(pThis, &StreamDesc, u32CblLimit, &cbAvail, &cbWritten);
    25792685#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    25802686                break;
    25812687            case PO_INDEX:
    25822688#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    2583                 cb = hdaWriteAudio(pThis, &StreamDesc, &cbAvail, &fStop, u32CblLimit);
     2689                rc = hdaWriteAudio(pThis, &StreamDesc, u32CblLimit, &cbAvail, &cbWritten);
    25842690#else
    2585                 cb = hdaWriteAudio(pThis, &StreamDesc, (uint32_t *)&cbAvail, &fStop, u32CblLimit);
     2691                rc = hdaWriteAudio(pThis, &StreamDesc, u32CblLimit, &cbAvail, &cbWritten);
    25862692#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    25872693                break;
     
    25902696            case MC_INDEX:
    25912697                pSink = pThis->pSinkMicIn;
    2592                 cb = hdaReadAudio(pThis, pSink, pBdle, &StreamDesc, &cbAvail, &fStop, u32CblLimit);
     2698                rc = hdaReadAudio(pThis, pSink, &StreamDesc, u32CblLimit, &cbAvail, &cbWritten);
    25932699                break;
    25942700# endif
    25952701#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    25962702            default:
    2597                 cb = 0;
    2598                 fStop = true;
    2599                 AssertMsgFailedReturnVoid(("Unsupported source index %d\n", enmSrc));
     2703                AssertMsgFailed(("Unsupported source index %ld\n", enmSrc));
     2704                rc = VERR_NOT_SUPPORTED;
    26002705                break;
    26012706        }
    2602         Assert(cb <= StreamDesc.u32Fifos + 1);
     2707        Assert(cbWritten <= StreamDesc.u32Fifos + 1);
    26032708        *StreamDesc.pu32Sts &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
    26042709
    26052710        /* Process end of buffer condition. */
    2606         hdaStreamCounterUpdate(pThis, pBdle, &StreamDesc, cb);
    2607         fStop = !fStop ? !hdaDoNextTransferCycle(pThis, pBdle, &StreamDesc) : fStop;
    2608     }
     2711        hdaStreamCounterUpdate(pThis, pBdle, &StreamDesc, cbWritten);
     2712
     2713        if (   !hdaDoNextTransferCycle(pThis, pBdle, &StreamDesc)
     2714            || RT_FAILURE(rc))
     2715        {
     2716            if (rc == VERR_NO_DATA) /* No more data to process. */
     2717                rc = VINF_SUCCESS;
     2718
     2719            break;
     2720        }
     2721    }
     2722
     2723    return rc;
    26092724}
    26102725#endif /* IN_RING3 */
     
    28712986            else
    28722987            {
    2873                 LogRel(("Invalid write access @0x%x!\n", offReg));
     2988                LogRel(("HDA: Invalid write access @0x%x!\n", offReg));
    28742989                cbReg = 1;
    28752990            }
     
    30163131{
    30173132    PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
     3133
    30183134    /* Save Codec nodes states */
    3019 #if 0
    3020     /** @todo Handle LUNs > 0! */
    3021     hdaCodecSaveState(pThis->pCodec[0], pSSM);
    3022 #else
    30233135    hdaCodecSaveState(pThis->pCodec, pSSM);
    3024 #endif
    30253136
    30263137    /* Save MMIO registers */
     
    30493160     * Load Codec nodes states.
    30503161     */
    3051 #if 0
    3052     /** @todo Handle LUNs > 0! */
    3053     int rc = hdaCodecLoadState(pThis->pCodec[0], pSSM, uVersion);
    3054 #else
    30553162    int rc = hdaCodecLoadState(pThis->pCodec, pSSM, uVersion);
    3056 #endif
    30573163    if (RT_FAILURE(rc))
    30583164        return rc;
     
    31193225     */
    31203226    bool fEnableIn    = RT_BOOL(SDCTL(pThis, 0) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
     3227#ifdef VBOX_WITH_HDA_MIC_IN
    31213228    bool fEnableMicIn = RT_BOOL(SDCTL(pThis, 2) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
     3229#endif
    31223230    bool fEnableOut   = RT_BOOL(SDCTL(pThis, 4) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
    31233231
    31243232#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    3125     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    3126     {
    3127         rc = pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmIn,
    3128                                                         fEnableIn);
     3233    PHDADRIVER pDrv;
     3234    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     3235    {
     3236        rc = pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn,
     3237                                           fEnableIn);
    31293238        if (RT_FAILURE(rc))
    31303239            break;
    3131         rc = pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmMic,
    3132                                                         fEnableMicIn);
     3240# ifdef VBOX_WITH_HDA_MIC_IN
     3241        rc = pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn,
     3242                                           fEnableMicIn);
    31333243        if (RT_FAILURE(rc))
    31343244            break;
    3135         rc = pThis->paDrv[lun]->pConnector->pfnEnableOut(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pGstStrmOut,
    3136                                                          fEnableOut);
     3245# endif
     3246        rc = pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut,
     3247                                            fEnableOut);
    31373248        if (RT_FAILURE(rc))
    31383249            break;
     
    33153426}
    33163427
     3428
    33173429/**
    33183430 * @callback_method_impl{FNDBGFHANDLERDEV}
     
    33213433{
    33223434    PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
    3323 #if 0
    3324     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    3325     {
    3326         if (pThis->pCodec[lun]->pfnCodecDbgListNodes)
    3327             pThis->pCodec[lun]->pfnCodecDbgListNodes(pThis->pCodec[lun], pHlp, pszArgs);
    3328         else
    3329             pHlp->pfnPrintf(pHlp, "Codec implementation for LUN #%RU8 doesn't provide corresponding callback\n", lun);
    3330     }
    3331 #else
     3435
    33323436    if (pThis->pCodec->pfnCodecDbgListNodes)
    33333437        pThis->pCodec->pfnCodecDbgListNodes(pThis->pCodec, pHlp, pszArgs);
    33343438    else
    33353439        pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
    3336 #endif
    33373440}
    33383441
     
    33443447{
    33453448    PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
    3346 #if 0
    3347     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    3348     {
    3349         if (pThis->pCodec[lun]->pfnCodecDbgSelector)
    3350             pThis->pCodec[lun]->pfnCodecDbgSelector(pThis->pCodec[lun], pHlp, pszArgs);
    3351         else
    3352             pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
    3353     }
    3354 #else
     3449
    33553450    if (pThis->pCodec->pfnCodecDbgSelector)
    33563451        pThis->pCodec->pfnCodecDbgSelector(pThis->pCodec, pHlp, pszArgs);
    33573452    else
    33583453        pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
    3359 #endif
    33603454}
    33613455
     
    34043498#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    34053499    /* Stop any audio currently playing. */
    3406     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    3407     {
    3408         pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmIn,
    3409                                                   false /* Disable */);
     3500    PHDADRIVER pDrv;
     3501    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     3502    {
     3503        pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, false /* Disable */);
    34103504        /* Ignore rc. */
    3411         pThis->paDrv[lun]->pConnector->pfnEnableIn(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pStrmMic,
    3412                                                    false /* Disable */);
     3505        pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, false /* Disable */);
    34133506        /* Ditto. */
    3414         pThis->paDrv[lun]->pConnector->pfnEnableOut(pThis->paDrv[lun]->pConnector, pThis->paDrv[lun]->pGstStrmOut,
    3415                                                     false /* Disable */);
     3507        pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, false /* Disable */);
    34163508        /* Ditto. */
    34173509    }
     
    34433535        if (u8Strm == 0)
    34443536            pBdle = &pThis->StInBdle;
     3537# ifdef VBOX_WITH_HDA_MIC_IN
    34453538        else if (u8Strm == 2)
    34463539            pBdle = &pThis->StMicBdle;
     3540# endif
    34473541        else if(u8Strm == 4)
    34483542            pBdle = &pThis->StOutBdle;
     
    34583552    }
    34593553
    3460     /* emulation of codec "wake up" (HDA spec 5.5.1 and 6.5)*/
     3554    /* Emulation of codec "wake up" (HDA spec 5.5.1 and 6.5). */
    34613555    HDA_REG(pThis, STATESTS) = 0x1;
    34623556
    3463     LogFunc(("Reset finished\n"));
     3557    LogRel(("HDA: Reset\n"));
    34643558}
    34653559
     
    34713565    PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
    34723566
     3567#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     3568    PHDADRIVER pDrv;
     3569    while (!RTListIsEmpty(&pThis->lstDrv))
     3570    {
     3571        pDrv = RTListGetFirst(&pThis->lstDrv, HDADRIVER, Node);
     3572
     3573        RTListNodeRemove(&pDrv->Node);
     3574        RTMemFree(pDrv);
     3575    }
     3576
     3577    if (pThis->pMixer)
     3578    {
     3579        audioMixerDestroy(pThis->pMixer);
     3580        pThis->pMixer = NULL;
     3581    }
     3582#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
     3583
    34733584    if (pThis->pCodec)
    34743585    {
     
    34793590        pThis->pCodec = NULL;
    34803591    }
    3481 
    3482 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    3483     for (uint8_t lun = 0; lun < pThis->cLUNs; lun++)
    3484     {
    3485         if (pThis->paDrv[lun])
    3486         {
    3487             RTMemFree(pThis->paDrv[lun]);
    3488             pThis->paDrv[lun] = NULL;
    3489         }
    3490     }
    3491 
    3492     if (pThis->pMixer)
    3493     {
    3494         audioMixerDestroy(pThis->pMixer);
    3495         pThis->pMixer = NULL;
    3496     }
    3497 
    3498     pThis->cLUNs = 0;
    3499 #else
    3500     if (pThis->pCodec)
    3501     {
    3502         int rc = hdaCodecDestruct(pThis->pCodec);
    3503         AssertRC(rc);
    3504 
    3505         RTMemFree(pThis->pCodec);
    3506         pThis->pCodec = NULL;
    3507     }
    3508 #endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    35093592
    35103593    RTMemFree(pThis->pu32CorbBuf);
     
    35423625     */
    35433626    char *pszDesc = NULL;
    3544     if (RTStrAPrintf(&pszDesc, "Audio driver port (HDA) for LUN #%u", uLUN) <= 0)
     3627    if (RTStrAPrintf(&pszDesc, "Audio driver port (HDA) for LUN#%u", uLUN) <= 0)
    35453628        AssertMsgReturn(pszDesc,
    35463629                        ("Not enough memory for HDA driver port description of LUN #%u\n", uLUN),
     
    35563639            pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIAUDIOCONNECTOR);
    35573640            AssertMsg(pDrv->pConnector != NULL,
    3558                       ("Configuration error: LUN #%u has no host audio interface, rc=%Rrc\n",
     3641                      ("Configuration error: LUN#%u has no host audio interface, rc=%Rrc\n",
    35593642                      uLUN, rc));
    35603643            pDrv->pHDAState = pThis;
    3561             pDrv->uLUN = uLUN;
     3644            pDrv->uLUN      = uLUN;
    35623645
    35633646            /*
     
    35683651                pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
    35693652
    3570             LogFunc(("LUN #%u: pCon=%p, drvFlags=0x%x\n",
    3571                      uLUN, pDrv->pConnector, pDrv->Flags));
    3572 
    3573             pThis->paDrv[uLUN] = pDrv;
    3574             pThis->cLUNs++;
     3653            LogFunc(("LUN#%u: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
     3654
     3655            /* Attach to driver list. */
     3656            RTListAppend(&pThis->lstDrv, &pDrv->Node);
    35753657        }
    35763658        else
    35773659            rc = VERR_NO_MEMORY;
    35783660    }
    3579     else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
     3661    else if (   rc == VERR_PDM_NO_ATTACHED_DRIVER
     3662             || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
    35803663    {
    35813664        LogFunc(("No attached driver for LUN #%u\n", uLUN));
     
    35873670    RTStrFree(pszDesc);
    35883671
    3589     LogFunc(("iLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
     3672    LogFunc(("uLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
    35903673    return rc;
    35913674}
     
    37413824
    37423825#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    3743     /* We support 32 LUNs max. This should be enough for now. */
    3744     for (uint8_t lun = 0; lun < 32 ; lun++)
    3745     {
    3746         LogFunc(("Trying to attach driver for LUN #%RU32 ...\n", lun));
    3747         rc = hdaAttach(pDevIns, lun, PDM_TACH_FLAGS_NOT_HOT_PLUG);
     3826    RTListInit(&pThis->lstDrv);
     3827
     3828    unsigned uLUN = 0;
     3829    do
     3830    {
     3831        LogFunc(("Trying to attach driver for LUN #%RU32 ...\n", uLUN));
     3832        rc = hdaAttach(pDevIns, uLUN++, PDM_TACH_FLAGS_NOT_HOT_PLUG);
    37483833        if (RT_FAILURE(rc))
    37493834        {
    37503835            if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
    37513836                rc = VINF_SUCCESS;
     3837
    37523838            break;
    37533839        }
    3754     }
     3840
     3841    } while (RT_SUCCESS(rc));
    37553842
    37563843    if (RT_SUCCESS(rc))
     
    37803867    }
    37813868
    3782     LogFunc(("cLUNs=%RU8, rc=%Rrc\n", pThis->cLUNs, rc));
     3869    LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
    37833870#else
    37843871    /*
     
    38253912        PCIDevSetSubSystemId(      &pThis->PciDev, pThis->pCodec->u16DeviceId); /* 2e ro. */
    38263913
     3914#ifndef VBOX_WITH_PDM_AUDIO_DRIVER
    38273915        pThis->pCodec->pfnTransfer = hdaTransfer;
    3828         pThis->pCodec->pfnReset = hdaCodecReset;
     3916#endif
     3917        pThis->pCodec->pfnReset    = hdaCodecReset;
    38293918    }
    38303919
     
    39033992    #endif
    39043993
    3905             /* The final entry is a full dword, no gaps! Allows shortcuts. */
     3994            /* The final entry is a full DWORD, no gaps! Allows shortcuts. */
    39063995            AssertReleaseMsg(pNextReg || ((pReg->offset + pReg->size) & 3) == 0,
    39073996                             ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
    39083997        }
    39093998    }
     3999
     4000#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     4001    if (RT_SUCCESS(rc))
     4002    {
     4003        /* Start the emulation timer. */
     4004        rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, hdaTimer, pThis,
     4005                                    TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchHda", &pThis->pTimer);
     4006        AssertRCReturn(rc, rc);
     4007
     4008        if (RT_SUCCESS(rc))
     4009        {
     4010            /** @todo Investigate why sounds is getting corrupted if the "ticks" value is too
     4011             *        low, e.g. "PDMDevHlpTMTimeVirtGetFreq / 200". */
     4012            pThis->uTicks = PDMDevHlpTMTimeVirtGetFreq(pDevIns) / 500; /** @todo Make this configurable! */
     4013            if (pThis->uTicks < 100)
     4014                pThis->uTicks = 100;
     4015            LogFunc(("Timer ticks=%RU64\n", pThis->uTicks));
     4016
     4017            /* Fire off timer. */
     4018            TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->uTicks);
     4019        }
     4020    }
     4021
     4022# ifdef VBOX_WITH_STATISTICS
     4023    if (RT_SUCCESS(rc))
     4024    {
     4025        /*
     4026         * Register statistics.
     4027         */
     4028        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer,            STAMTYPE_PROFILE, "/Devices/HDA/Timer",             STAMUNIT_TICKS_PER_CALL, "Profiling hdaTimer.");
     4029        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead,        STAMTYPE_COUNTER, "/Devices/HDA/BytesRead"   ,      STAMUNIT_BYTES,          "Bytes read from HDA emulation.");
     4030        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten,     STAMTYPE_COUNTER, "/Devices/HDA/BytesWritten",      STAMUNIT_BYTES,          "Bytes written to HDA emulation.");
     4031    }
     4032# endif
     4033
     4034#endif
    39104035
    39114036    LogFlowFuncLeaveRC(rc);
  • trunk/src/VBox/Devices/Audio/DrvAudio.cpp

    r53624 r53830  
    884884    }
    885885
    886     LogFlowFunc(("pvBuf=%p, cbBuf=%zu, cWritten=%RU32 (%zu bytes), cMixed=%RU32, rc=%Rrc\n",
     886    LogFlowFunc(("Written pvBuf=%p, cbBuf=%zu, cWritten=%RU32 (%RU32 bytes), cMixed=%RU32, rc=%Rrc\n",
    887887                 pvBuf, cbBuf, cWritten, AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cWritten),
    888888                 cMixed, rc));
     
    984984}
    985985
    986 static int drvAudioPlayOut(PDRVAUDIO pThis)
    987 {
     986static DECLCALLBACK(int) drvAudioQueryData(PPDMIAUDIOCONNECTOR pInterface,
     987                                           uint32_t *pcbAvailIn, uint32_t *pcbFreeOut,
     988                                           uint32_t *pcSamplesLive)
     989{
     990    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     991
     992    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
     993
     994    int rc = VINF_SUCCESS;
     995    uint32_t cSamplesLive = 0;
     996
    988997    /*
    989      * Process all enabled host output streams.
     998     * Playback.
    990999     */
     1000    uint32_t cbFreeOut = UINT32_MAX;
     1001
    9911002    PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
    9921003    while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
    9931004    {
    9941005        uint32_t cStreamsLive;
    995         uint32_t cSamplesLive = drvAudioHstOutSamplesLive(pHstStrmOut, &cStreamsLive);
     1006        cSamplesLive = drvAudioHstOutSamplesLive(pHstStrmOut, &cStreamsLive);
    9961007        if (!cStreamsLive)
    9971008            cSamplesLive = 0;
     
    10091020                pHstStrmOut->fEnabled        = false;
    10101021                pHstStrmOut->fPendingDisable = false;
     1022
     1023                LogFunc(("%p: Disabling stream\n", pHstStrmOut));
    10111024            }
    10121025            else
    1013                 LogFlowFunc(("Backend vetoed closing output stream, rc=%Rrc\n", rc2));
     1026                LogFunc(("%p: Backend vetoed against closing output stream, rc=%Rrc\n",
     1027                         pHstStrmOut, rc2));
    10141028
    10151029            continue;
    10161030        }
     1031
     1032        LogFlowFunc(("%p: Has %RU32 live samples\n", pHstStrmOut, cSamplesLive));
    10171033
    10181034        /*
     
    10261042        if (!cSamplesLive)
    10271043        {
    1028             LogFlowFunc(("No live samples available\n"));
    1029 
    1030             uint32_t cbFree;
     1044            uint32_t cbFree2 = UINT32_MAX;
    10311045            RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
    10321046            {
     
    10351049                    /* Tell the sound device emulation how many samples are free
    10361050                     * so that it can start writing PCM data to us. */
    1037                     cbFree = AUDIOMIXBUF_S2B_RATIO(&pGstStrmOut->MixBuf,
    1038                                                    audioMixBufFree(&pGstStrmOut->MixBuf));
    1039                     if (cbFree)
    1040                     {
    1041                         LogFlowFunc(("cbFree=%RU32\n", cbFree));
    1042                         pGstStrmOut->Callback.fn(pGstStrmOut->Callback.pvContext, cbFree);
    1043                     }
     1051                    cbFree2 = RT_MIN(cbFree2, AUDIOMIXBUF_S2B_RATIO(&pGstStrmOut->MixBuf,
     1052                                                                    audioMixBufFree(&pGstStrmOut->MixBuf)));
    10441053                }
    10451054            }
     1055
     1056            cbFreeOut = RT_MIN(cbFreeOut, cbFree2);
     1057            continue;
     1058        }
     1059    }
     1060
     1061    /*
     1062     * Recording.
     1063     */
     1064    uint32_t cbAvailIn = 0;
     1065
     1066    PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
     1067    while ((pHstStrmIn = drvAudioFindNextEnabledHstIn(pThis, pHstStrmIn)))
     1068    {
     1069        /* Call the host backend to capture the audio input data. */
     1070        uint32_t cSamplesCaptured;
     1071        int rc2 = pThis->pHostDrvAudio->pfnCaptureIn(pThis->pHostDrvAudio, pHstStrmIn,
     1072                                                     &cSamplesCaptured);
     1073        if (RT_FAILURE(rc2))
     1074            continue;
     1075
     1076        PPDMAUDIOGSTSTRMIN pGstStrmIn = pHstStrmIn->pGstStrmIn;
     1077        AssertPtrBreak(pGstStrmIn);
     1078
     1079        if (pGstStrmIn->State.fActive)
     1080        {
     1081            cbAvailIn = RT_MAX(cbAvailIn, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf,
     1082                                                          audioMixBufMixed(&pHstStrmIn->MixBuf)));
     1083        }
     1084    }
     1085
     1086    if (RT_SUCCESS(rc))
     1087    {
     1088        if (cbFreeOut == UINT32_MAX)
     1089            cbFreeOut = 0;
     1090
     1091        if (pcbAvailIn)
     1092            *pcbAvailIn = cbAvailIn;
     1093
     1094        if (pcbFreeOut)
     1095            *pcbFreeOut = cbFreeOut;
     1096
     1097        if (pcSamplesLive)
     1098            *pcSamplesLive = cSamplesLive;
     1099    }
     1100
     1101    return rc;
     1102}
     1103
     1104static DECLCALLBACK(int) drvAudioPlayOut(PPDMIAUDIOCONNECTOR pInterface)
     1105{
     1106    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     1107    /* pcbFree is optional. */
     1108
     1109    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
     1110
     1111    int rc = VINF_SUCCESS;
     1112
     1113    /*
     1114     * Process all enabled host output streams.
     1115     */
     1116    PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
     1117    while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
     1118    {
     1119        uint32_t cStreamsLive;
     1120        uint32_t cSamplesLive = drvAudioHstOutSamplesLive(pHstStrmOut, &cStreamsLive);
     1121        if (!cStreamsLive)
     1122            cSamplesLive = 0;
     1123
     1124        /* Has this stream marked as disabled but there still were guest streams relying
     1125         * on it? Check if this stream now can be closed and do so, if possible. */
     1126        if (   pHstStrmOut->fPendingDisable
     1127            && !cStreamsLive)
     1128        {
     1129            /* Stop playing the current (pending) stream. */
     1130            int rc2 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut,
     1131                                                          PDMAUDIOSTREAMCMD_DISABLE);
     1132            if (RT_SUCCESS(rc2))
     1133            {
     1134                pHstStrmOut->fEnabled        = false;
     1135                pHstStrmOut->fPendingDisable = false;
     1136
     1137                LogFunc(("\t%p: Disabling stream\n", pHstStrmOut));
     1138            }
     1139            else
     1140                LogFunc(("\t%p: Backend vetoed against closing output stream, rc=%Rrc\n",
     1141                         rc2, pHstStrmOut));
    10461142
    10471143            continue;
     
    10511147        int rc2 = pThis->pHostDrvAudio->pfnPlayOut(pThis->pHostDrvAudio, pHstStrmOut,
    10521148                                                   &cSamplesPlayed);
    1053         LogFlowFunc(("%p: cStreamsLive=%RU32, cSamplesLive=%RU32, cSamplesPlayed=%RU32, rc=%Rrc\n",
     1149        LogFlowFunc(("\t%p: cStreamsLive=%RU32, cSamplesLive=%RU32, cSamplesPlayed=%RU32, rc=%Rrc\n",
    10541150                     pHstStrmOut, cStreamsLive, cSamplesLive, cSamplesPlayed, rc2));
    10551151
    10561152        bool fNeedsCleanup = false;
    1057         uint32_t cbFree;
     1153
     1154        PPDMAUDIOGSTSTRMOUT pGstStrmOut;
    10581155        RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
    10591156        {
     
    10681165                                 && !pGstStrmOut->Callback.fn;
    10691166            }
    1070 
    1071             if (pGstStrmOut->State.fActive)
    1072             {
    1073                 /* Tell the device emulation how many samples are free so that it can start
    1074                  * writing PCM data to us. */
    1075                 cbFree = AUDIOMIXBUF_S2B_RATIO(&pGstStrmOut->MixBuf,
    1076                                                audioMixBufFree(&pGstStrmOut->MixBuf));
    1077                 if (cbFree)
    1078                 {
    1079                     LogFlowFunc(("cbFree=%RU32\n", cbFree));
    1080                     pGstStrmOut->Callback.fn(pGstStrmOut->Callback.pvContext, cbFree);
    1081                 }
    1082             }
    10831167        }
    10841168
     
    10871171            RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
    10881172            {
    1089                 if (   !pGstStrmOut->State.fActive
    1090                     && !pGstStrmOut->Callback.fn)
    1091                 {
     1173                if (!pGstStrmOut->State.fActive)
    10921174                    drvAudioDestroyGstOut(pThis, pGstStrmOut);
    1093                 }
    10941175            }
    10951176        }
    10961177    }
    10971178
    1098     return VINF_SUCCESS;
    1099 }
    1100 
    1101 /**
    1102  * Notifies the device emulation of newly available (captured) host input data.
    1103  *
    1104  * @return  IPRT status code.
    1105  * @param   pThis               Pointer to audio driver instance.
    1106  */
    1107 static int drvAudioSendIn(PDRVAUDIO pThis)
    1108 {
    1109     AssertPtrReturn(pThis, VERR_INVALID_POINTER);
    1110 
    1111     PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
    1112     while ((pHstStrmIn = drvAudioFindNextEnabledHstIn(pThis, pHstStrmIn)))
    1113     {
    1114         /* Call the host backend to capture the audio input data. */
    1115         uint32_t cSamplesCaptured;
    1116         int rc2 = pThis->pHostDrvAudio->pfnCaptureIn(pThis->pHostDrvAudio, pHstStrmIn,
    1117                                                      &cSamplesCaptured);
    1118         if (RT_FAILURE(rc2))
    1119             continue;
    1120 
    1121         PPDMAUDIOGSTSTRMIN pGstStrmIn = pHstStrmIn->pGstStrmIn;
    1122         AssertPtrBreak(pGstStrmIn);
    1123 
    1124         if (pGstStrmIn->State.fActive)
    1125         {
    1126             uint32_t cbData = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf,
    1127                                               audioMixBufMixed(&pHstStrmIn->MixBuf));
    1128             if (cbData)
    1129             {
    1130                 /*
    1131                  * Tell the device emulation how many audio input bytes are available
    1132                  * to process (and to write to the device itself).
    1133                  */
    1134                 LogFlowFunc(("cbData=%RU32\n", cbData));
    1135                 pGstStrmIn->Callback.fn(pGstStrmIn->Callback.pvContext, cbData);
    1136             }
    1137         }
    1138     }
    1139 
    1140     return VINF_SUCCESS;
    1141 }
    1142 
    1143 static void drvAudioTimer(PDRVAUDIO pThis)
    1144 {
    1145     drvAudioPlayOut(pThis);
    1146     drvAudioSendIn(pThis);
    1147 
    1148     AssertPtr(pThis->pTimer);
    1149     int rc = TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->uTicks);
    1150     AssertRC(rc);
     1179    return rc;
    11511180}
    11521181
     
    12551284}
    12561285
    1257 static DECLCALLBACK(void) drvAudioTimerHelper(PPDMDRVINS pDrvIns, PTMTIMER pTimer, void *pvUser)
    1258 {
    1259     PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
    1260     drvAudioTimer(pThis);
    1261 }
    1262 
    12631286static struct audio_option audio_options[] =
    12641287{
     
    13161339    RTListInit(&pThis->lstHstStrmOut);
    13171340
    1318     int rc;
     1341    int rc = VINF_SUCCESS;
    13191342
    13201343    /* Get the configuration data from the selected backend (if available). */
     
    13221345    if (RT_LIKELY(pThis->pHostDrvAudio->pfnGetConf))
    13231346        rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
    1324     else
    1325         AssertMsgFailed(("No audio backend configuration given\n"));
    13261347
    13271348    if (RT_SUCCESS(rc))
    13281349    {
    1329         LogFlowFunc(("Creating timer ...\n"));
    1330         rc = PDMDrvHlpTMTimerCreate(pDrvIns, TMCLOCK_VIRTUAL, drvAudioTimerHelper,
    1331                                     pThis, TMTIMER_FLAGS_DEFAULT_CRIT_SECT,
    1332                                     "Audio emulation timer", &pThis->pTimer);
    1333         if (RT_FAILURE(rc))
    1334         {
    1335             LogFlowFunc(("Failed to create timer, rc=%Rrc\n", rc));
    1336             return rc;
    1337         }
    1338     }
    1339 
    1340     rc = drvAudioProcessOptions(pCfgHandle, "AUDIO", audio_options);
    1341     /** @todo Check for invalid options? */
    1342 
    1343     pThis->cFreeOutputStreams = conf.fixed_out.cStreams;
    1344     pThis->cFreeInputStreams = conf.fixed_in.cStreams;
    1345 
    1346     if (!pThis->cFreeOutputStreams)
    1347     {
    1348         LogFlowFunc(("Bogus number of playback voices %d, setting to 1\n",
    1349                      pThis->cFreeOutputStreams));
    1350         pThis->cFreeOutputStreams = 1;
    1351     }
    1352 
    1353     if (!pThis->cFreeInputStreams)
    1354     {
    1355         LogFlowFunc(("Bogus number of capture voices %d, setting to 1\n",
    1356                      pThis->cFreeInputStreams));
    1357         pThis->cFreeInputStreams = 1;
    1358     }
    1359 
    1360     /* Initialization of audio buffers. Create ring buffer of 768 each. */
    1361     rc = RTCircBufCreate(&pThis->pAudioWriteBuf, 768 * 1024);
    1362     if (RT_SUCCESS(rc))
    1363     {
    1364         /* Allocating space for about 500 msec of audio data 48KHz, 128 bit sample
    1365          * (guest format - PDMHOSTSTEREOSAMPLE) and dual channel.
    1366          */
    1367         rc = RTCircBufCreate(&pThis->pAudioReadBuf, 768 * 1024);
     1350        rc = drvAudioProcessOptions(pCfgHandle, "AUDIO", audio_options);
     1351        /** @todo Check for invalid options? */
     1352
     1353        pThis->cFreeOutputStreams = conf.fixed_out.cStreams;
     1354        pThis->cFreeInputStreams  = conf.fixed_in.cStreams;
     1355
     1356        if (!pThis->cFreeOutputStreams)
     1357            pThis->cFreeOutputStreams = 1;
     1358
     1359        if (!pThis->cFreeInputStreams)
     1360            pThis->cFreeInputStreams = 1;
    13681361    }
    13691362
     
    13741367        rc = drvAudioHostInit(pCfgHandle, pThis);
    13751368
    1376     if (RT_SUCCESS(rc))
    1377     {
    1378         if (conf.period.hz <= 0)
    1379             pThis->uTicks = 100; /* Don't stress CPU too much. */
    1380         else
    1381             pThis->uTicks = PDMDrvHlpTMGetVirtualFreq(pDrvIns) / conf.period.hz;
    1382     }
    1383 
    1384     if (   RT_SUCCESS(rc)
    1385         && pThis->pTimer)
    1386     {
    1387         LogFlowFunc(("Timer ticks=%RU64, hz=%d\n", pThis->uTicks, conf.period.hz));
    1388 
    1389         /* Fire off timer. */
    1390         TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->uTicks);
    1391     }
    1392     else
    1393     {
    1394         if (pThis->pTimer)
    1395             TMR3TimerDestroy(pThis->pTimer);
    1396     }
    1397 
    13981369    LogFlowFuncLeaveRC(rc);
    13991370    return rc;
     
    14041375    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
    14051376    NOREF(pThis);
     1377
     1378    LogRel(("Audio: Using NULL driver; no sound will be audible\n"));
    14061379
    14071380    /* Nothing to do here yet. */
     
    18621835    pDrvIns->IBase.pfnQueryInterface                 = drvAudioQueryInterface;
    18631836    /* IAudio. */
     1837    pThis->IAudioConnector.pfnQueryData              = drvAudioQueryData;
    18641838    pThis->IAudioConnector.pfnRead                   = drvAudioRead;
    18651839    pThis->IAudioConnector.pfnWrite                  = drvAudioWrite;
     
    18751849    pThis->IAudioConnector.pfnOpenIn                 = drvAudioOpenIn;
    18761850    pThis->IAudioConnector.pfnOpenOut                = drvAudioOpenOut;
     1851    pThis->IAudioConnector.pfnPlayOut                = drvAudioPlayOut;
    18771852    pThis->IAudioConnector.pfnIsActiveIn             = drvAudioIsActiveIn;
    18781853    pThis->IAudioConnector.pfnIsActiveOut            = drvAudioIsActiveOut;
Note: See TracChangeset for help on using the changeset viewer.

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