VirtualBox

Ignore:
Timestamp:
Dec 21, 2016 1:21:11 PM (8 years ago)
Author:
vboxsync
Message:

Audio/DevIchAc97.cpp: Added initial support for async I/O handling to decouple the DMA data processing from the backend work. Work in progress.

File:
1 edited

Legend:

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

    r64570 r64980  
    3131# endif
    3232# include <iprt/mem.h>
     33# include <iprt/semaphore.h>
    3334# include <iprt/string.h>
    3435# include <iprt/uuid.h>
     
    4546*   Defined Constants And Macros                                                                                                 *
    4647*********************************************************************************************************************************/
     48
     49/*
     50 * Enables asynchronous audio data handling
     51 * to speed up the actual DMA data routines and keeping up
     52 * audio processing out of EMT as much as possible.
     53 */
     54#define VBOX_WITH_AUDIO_AC97_ASYNC_IO
    4755
    4856#if 0
     
    6371#define AC97_SSM_VERSION    1
    6472
    65 /** Timer frequency (in Hz) */
    66 #define AC97_TIMER_HZ       200
     73/** Default timer frequency (in Hz). */
     74#define AC97_TIMER_HZ       100
    6775
    6876#define AC97_SR_FIFOE RT_BIT(4)          /* rwc, FIFO error. */
     
    281289} AC97BMREGS, *PAC97BMREGS;
    282290
    283 /**
    284  * Internal state of an AC'97 stream.
     291#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     292/**
     293 * Structure keeping the AC'97 stream's state for asynchronous I/O.
     294 */
     295typedef struct AC97STREAMSTATEAIO
     296{
     297    /** Thread handle for the actual I/O thread. */
     298    RTTHREAD              Thread;
     299    /** Event for letting the thread know there is some data to process. */
     300    RTSEMEVENT            Event;
     301    /** Critical section for synchronizing access. */
     302    RTCRITSECT            CritSect;
     303    /** Started indicator. */
     304    volatile bool         fStarted;
     305    /** Shutdown indicator. */
     306    volatile bool         fShutdown;
     307    uint32_t              Padding1;
     308} AC97STREAMSTATEAIO, *PAC97STREAMSTATEAIO;
     309#endif
     310
     311/**
     312 * Structure for keeping the internal state of an AC'97 stream.
    285313 */
    286314typedef struct AC97STREAMSTATE
    287315{
    288     /** Temporary FIFO write buffer. */
    289     R3PTRTYPE(uint8_t *) au8FIFOW;
    290     /** Size of the temporary FIFO write buffer. */
    291     uint32_t             cbFIFOW;
    292     /** Current write offset in FIFO write buffer. */
    293     uint32_t             offFIFOW;
    294     uint8_t              Padding;
     316    /** Circular buffer (FIFO) for holding DMA'ed data. */
     317    R3PTRTYPE(PRTCIRCBUF) pCircBuf;
     318#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     319    /** Asynchronous I/O state members. */
     320    AC97STREAMSTATEAIO    AIO;
     321#endif
    295322} AC97STREAMSTATE, *PAC97STREAMSTATE;
    296323
    297324/**
    298  * Structure for keeping an AC'97 stream state.
     325 * Structure for an AC'97 stream.
    299326 */
    300327typedef struct AC97STREAM
     
    310337} AC97STREAM, *PAC97STREAM;
    311338
    312 typedef struct AC97INPUTSTREAM
    313 {
    314     /** Mixer handle for input stream. */
    315     R3PTRTYPE(PAUDMIXSTREAM) pMixStrm;
    316 } AC97INPUTSTREAM, *PAC97INPUTSTREAM;
    317 
    318 typedef struct AC97OUTPUTSTREAM
    319 {
    320     /** Mixer handle for output stream. */
    321     R3PTRTYPE(PAUDMIXSTREAM) pMixStrm;
    322 } AC97OUTPUTSTREAM, *PAC97OUTPUTSTREAM;
     339typedef struct AC97STATE *PAC97STATE;
     340#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     341/**
     342 * Structure for the async I/O thread context.
     343 */
     344typedef struct AC97STREAMTHREADCTX
     345{
     346    PAC97STATE  pThis;
     347    PAC97STREAM pStream;
     348} AC97STREAMTHREADCTX, *PAC97STREAMTHREADCTX;
     349#endif
     350
     351/**
     352 * Structure defining a (host backend) driver stream.
     353 * Each driver has its own instances of audio mixer streams, which then
     354 * can go into the same (or even different) audio mixer sinks.
     355 */
     356typedef struct AC97DRIVERSTREAM
     357{
     358    union
     359    {
     360        /** Desired playback destination (for an output stream). */
     361        PDMAUDIOPLAYBACKDEST           Dest;
     362        /** Desired recording source (for an input stream). */
     363        PDMAUDIORECSOURCE              Source;
     364    } DestSource;
     365    uint8_t                            Padding1[4];
     366    /** Associated mixer stream handle. */
     367    R3PTRTYPE(PAUDMIXSTREAM)           pMixStrm;
     368} AC97DRIVERSTREAM, *PAC97DRIVERSTREAM;
    323369
    324370/**
    325371 * Struct for maintaining a host backend driver.
    326372 */
    327 typedef struct AC97STATE *PAC97STATE;
    328373typedef struct AC97DRIVER
    329374{
     
    344389    /** Audio connector interface to the underlying host backend. */
    345390    R3PTRTYPE(PPDMIAUDIOCONNECTOR)     pConnector;
    346     /** Stream for line input. */
    347     AC97INPUTSTREAM                    LineIn;
    348     /** Stream for mic input. */
    349     AC97INPUTSTREAM                    MicIn;
    350     /** Stream for output. */
    351     AC97OUTPUTSTREAM                   Out;
     391    /** Driver stream for line input. */
     392    AC97DRIVERSTREAM                   LineIn;
     393    /** Driver stream for mic input. */
     394    AC97DRIVERSTREAM                   MicIn;
     395    /** Driver stream for output. */
     396    AC97DRIVERSTREAM                   Out;
    352397} AC97DRIVER, *PAC97DRIVER;
    353398
     399/**
     400 * Structure for maintaining an AC'97 device state.
     401 */
    354402typedef struct AC97STATE
    355403{
     
    366414    uint32_t                last_samp;
    367415    uint8_t                 mixer_data[256];
    368     /** Stream state for line-in. */
     416    /** AC'97 stream for line-in. */
    369417    AC97STREAM              StreamLineIn;
    370     /** Stream state for microphone-in. */
     418    /** AC'97 stream for microphone-in. */
    371419    AC97STREAM              StreamMicIn;
    372     /** Stream state for output. */
     420    /** AC'97 stream for output. */
    373421    AC97STREAM              StreamOut;
    374422    /** Number of active (running) SDn streams. */
     
    392440#endif
    393441#ifdef VBOX_WITH_STATISTICS
    394     uint8_t                 Padding1;
    395442    STAMPROFILE             StatTimer;
     443    STAMPROFILE             StatIn;
     444    STAMPROFILE             StatOut;
    396445    STAMCOUNTER             StatBytesRead;
    397446    STAMCOUNTER             StatBytesWritten;
     
    425474#ifndef VBOX_DEVICE_STRUCT_TESTCASE
    426475
    427 static void ichac97DestroyIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource);
    428 static void ichac97DestroyOut(PAC97STATE pThis);
    429 DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID);
    430 static int ichac97StreamInit(PAC97STREAM pStream, uint8_t u8Strm);
    431 static void ichac97StreamDestroy(PAC97STREAM pStream);
    432 static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream);
    433 static int ichac97StreamReOpen(PAC97STATE pThis, PAC97STREAM pStream);
    434 static void ichac97StreamClose(PAC97STREAM pStream);
     476DECLINLINE(PAC97STREAM)   ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID);
     477static int                ichac97StreamCreate(PAC97STATE pThis, PAC97STREAM pStream, uint8_t u8Strm);
     478static void               ichac97StreamDestroy(PAC97STATE pThis, PAC97STREAM pStream);
     479static int                ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream);
     480static int                ichac97StreamReOpen(PAC97STATE pThis, PAC97STREAM pStream);
     481static int                ichac97StreamClose(PAC97STATE pThis, PAC97STREAM pStream);
     482
    435483static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns);
    436484#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    437 static void ichac97TimerMaybeStart(PAC97STATE pThis);
    438 static void ichac97TimerMaybeStop(PAC97STATE pThis);
     485static void               ichac97TimerMaybeStart(PAC97STATE pThis);
     486static void               ichac97TimerMaybeStop(PAC97STATE pThis);
    439487static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
    440488#endif
    441 static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed);
     489static int                ichac97DoDMA(PAC97STATE pThis, PAC97STREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t cbToProcess, uint32_t *pcbProcessed);
     490static void               ichac97DoTransfers(PAC97STATE pThis);
     491
     492#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     493static DECLCALLBACK(int)  ichac97StreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser);
     494static int                ichac97StreamAsyncIONotify(PAC97STATE pThis, PAC97STREAM pStream);
     495static void               ichac97StreamAsyncIOLock(PAC97STREAM pStream);
     496static void               ichac97StreamAsyncIOUnlock(PAC97STREAM pStream);
     497#endif
    442498
    443499static void ichac97WarmReset(PAC97STATE pThis)
     
    571627        return VINF_SUCCESS;
    572628
    573     const bool fIsEnabled = AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING;
    574 
    575     LogFunc(("[SD%RU8] fEnable=%RTbool, fIsEnabled=%RTbool, DCH=%RTbool, cStreamsActive=%RU8\n",
    576              pStream->u8Strm, fEnable, fIsEnabled, RT_BOOL(pStream->Regs.sr & AC97_SR_DCH), pThis->cStreamsActive));
     629    const AUDMIXSINKSTS stsSink = AudioMixerSinkGetStatus(pSink);
     630
     631    const bool fIsEnabled       = stsSink & AUDMIXSINK_STS_RUNNING;
     632    const bool fPendingDisable  = stsSink & AUDMIXSINK_STS_PENDING_DISABLE;
     633
     634    LogFunc(("[SD%RU8] fEnable=%RTbool, fIsEnabled=%RTbool, fPendingDisable=%RTbool, DCH=%RTbool, cStreamsActive=%RU8\n",
     635             pStream->u8Strm, fEnable, fIsEnabled, fPendingDisable, RT_BOOL(pStream->Regs.sr & AC97_SR_DCH), pThis->cStreamsActive));
    577636
    578637    int rc = VINF_SUCCESS;
    579638
    580     if (fEnable != fIsEnabled)
    581     {
    582         rc = ichac97StreamReOpen(pThis, pStream);
    583         if (RT_SUCCESS(rc))
    584             rc = AudioMixerSinkCtl(ichac97IndexToSink(pThis, pStream->u8Strm),
    585                                    fEnable ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE);
    586         if (RT_SUCCESS(rc))
    587         {
    588             if (!fEnable)
    589             {
    590                 if (pThis->cStreamsActive) /* Disable can be called mupltiple times. */
    591                     pThis->cStreamsActive--;
     639#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     640    ichac97StreamAsyncIOLock(pStream);
     641#endif
     642
     643    if (fEnable)
     644        rc = ichac97StreamOpen(pThis, pStream);
     645    else
     646        rc = ichac97StreamClose(pThis, pStream);
     647
     648    if (RT_SUCCESS(rc))
     649        rc = AudioMixerSinkCtl(ichac97IndexToSink(pThis, pStream->u8Strm),
     650                               fEnable ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE);
     651
     652#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     653    ichac97StreamAsyncIOUnlock(pStream);
     654#endif
     655
     656    if (RT_SUCCESS(rc))
     657    {
     658        if (!fEnable)
     659        {
     660            if (pThis->cStreamsActive) /* Disable can be called mupltiple times. */
     661                pThis->cStreamsActive--;
    592662
    593663#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    594                 ichac97TimerMaybeStop(pThis);
     664            ichac97TimerMaybeStop(pThis);
    595665#endif
    596             }
    597             else
    598             {
    599                 pThis->cStreamsActive++;
     666        }
     667        else
     668        {
     669            pThis->cStreamsActive++;
    600670#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    601                 ichac97TimerMaybeStart(pThis);
     671            ichac97TimerMaybeStart(pThis);
    602672#endif
    603             }
    604673        }
    605674    }
     
    622691    pRegs->lvi      = 0;
    623692
    624     ichac97StreamEnable(pThis, pStream, false /* fActive */);
     693    ichac97StreamEnable(pThis, pStream, false /* fEnable */);
    625694
    626695    ichac97StreamUpdateSR(pThis, pStream, AC97_SR_DCH); /** @todo Do we need to do that? */
     
    634703}
    635704
    636 static int ichac97StreamInit(PAC97STREAM pStream, uint8_t u8Strm)
     705/**
     706 * Creates an AC'97 stream.
     707 *
     708 * @returns IPRT status code.
     709 * @param   pThis               AC'97 state.
     710 * @param   pStream             AC'97 stream to create.
     711 * @param   u8Strm              Stream ID to assign AC'97 stream to.
     712 */
     713static int ichac97StreamCreate(PAC97STATE pThis, PAC97STREAM pStream, uint8_t u8Strm)
    637714{
    638715    AssertPtrReturn(pStream, VERR_INVALID_PARAMETER);
     
    640717    LogFunc(("[SD%RU8] pStream=%p\n", u8Strm, pStream));
    641718
    642     int rc = VINF_SUCCESS;
    643 
    644     pStream->u8Strm         = u8Strm;
    645     pStream->State.cbFIFOW  = _4K; /** @todo Make FIFOW size configurable. */
    646     pStream->State.offFIFOW = 0;
    647     pStream->State.au8FIFOW = (uint8_t *)RTMemAllocZ(pStream->State.cbFIFOW);
    648     if (pStream->State.au8FIFOW)
    649     {
    650         rc = RTCritSectInit(&pStream->CritSect);
    651     }
    652     else
    653         rc = VERR_NO_MEMORY;
     719    pStream->u8Strm = u8Strm;
     720
     721    int rc = RTCritSectInit(&pStream->CritSect);
     722    if (RT_SUCCESS(rc))
     723        rc = RTCircBufCreate(&pStream->State.pCircBuf, _4K); /** @todo Make this configurable. */
     724
     725#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     726    /*
     727     * Create async I/O stuff.
     728     */
     729    PAC97STREAMSTATEAIO pAIO = &pStream->State.AIO;
     730
     731    pAIO->fShutdown = false;
     732
     733    if (RT_SUCCESS(rc))
     734    {
     735        rc = RTSemEventCreate(&pAIO->Event);
     736        if (RT_SUCCESS(rc))
     737        {
     738            rc = RTCritSectInit(&pAIO->CritSect);
     739            if (RT_SUCCESS(rc))
     740            {
     741                AC97STREAMTHREADCTX Ctx = { pThis, pStream };
     742
     743                char szThreadName[64];
     744                RTStrPrintf2(szThreadName, sizeof(szThreadName), "ac97AIO%RU8", pStream->u8Strm);
     745
     746                /** @todo Create threads on demand? */
     747
     748                rc = RTThreadCreate(&pAIO->Thread, ichac97StreamAsyncIOThread, &Ctx,
     749                                    0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, szThreadName);
     750                if (RT_SUCCESS(rc))
     751                    rc = RTThreadUserWait(pAIO->Thread, 10 * 1000 /* 10s timeout */);
     752            }
     753        }
     754    }
     755#else
     756    RT_NOREF(pThis);
     757#endif
    654758
    655759    return rc;
    656760}
    657761
    658 static void ichac97StreamDestroy(PAC97STREAM pStream)
     762/**
     763 * Destroys an AC'97 stream.
     764 *
     765 * @returns IPRT status code.
     766 * @param   pThis               AC'97 state.
     767 * @param   pStream             AC'97 stream to destroy.
     768 */
     769static void ichac97StreamDestroy(PAC97STATE pThis, PAC97STREAM pStream)
    659770{
    660771    LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
    661772
    662     if (pStream->State.au8FIFOW)
    663     {
    664         Assert(pStream->State.cbFIFOW);
    665         RTMemFree(pStream->State.au8FIFOW);
    666         pStream->State.au8FIFOW = NULL;
    667     }
    668 
    669     pStream->State.cbFIFOW  = 0;
    670     pStream->State.offFIFOW = 0;
    671 
    672     if (RTCritSectIsInitialized(&pStream->CritSect))
    673         RTCritSectDelete(&pStream->CritSect);
    674 }
    675 
     773    int rc2 = RTCritSectDelete(&pStream->CritSect);
     774    AssertRC(rc2);
     775
     776    if (pStream->State.pCircBuf)
     777    {
     778        RTCircBufDestroy(pStream->State.pCircBuf);
     779        pStream->State.pCircBuf = NULL;
     780    }
     781
     782#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     783    /*
     784     * Destroy async I/O stuff.
     785     */
     786    PAC97STREAMSTATEAIO pAIO = &pStream->State.AIO;
     787
     788    if (ASMAtomicReadBool(&pAIO->fStarted))
     789    {
     790        ASMAtomicWriteBool(&pAIO->fShutdown, true);
     791
     792        rc2 = ichac97StreamAsyncIONotify(pThis, pStream);
     793        AssertRC(rc2);
     794
     795        int rcThread;
     796        rc2 = RTThreadWait(pAIO->Thread, 30 * 1000 /* 30s timeout */, &rcThread);
     797        LogFunc(("Async I/O thread ended with %Rrc (%Rrc)\n", rc2, rcThread));
     798
     799        if (RT_SUCCESS(rc2))
     800        {
     801            rc2 = RTCritSectDelete(&pAIO->CritSect);
     802            AssertRC(rc2);
     803
     804            rc2 = RTSemEventDestroy(pAIO->Event);
     805            AssertRC(rc2);
     806
     807            pAIO->fStarted  = false;
     808            pAIO->fShutdown = false;
     809        }
     810    }
     811#else
     812    RT_NOREF(pThis);
     813#endif
     814
     815    LogFlowFuncLeave();
     816}
     817
     818/**
     819 * Creates all AC'97 streams for the device.
     820 *
     821 * @returns IPRT status code.
     822 * @param   pThis               AC'97 state.
     823 */
    676824static int ichac97StreamsCreate(PAC97STATE pThis)
    677825{
     
    685833    int rc = AudioMixerCreateSink(pThis->pMixer, "[Recording] Line In", AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
    686834    if (RT_SUCCESS(rc))
    687         rc = ichac97StreamInit(&pThis->StreamLineIn, AC97SOUNDSOURCE_PI_INDEX);
     835        rc = ichac97StreamCreate(pThis, &pThis->StreamLineIn, AC97SOUNDSOURCE_PI_INDEX);
    688836
    689837    /* Microphone-In. */
     
    692840        rc = AudioMixerCreateSink(pThis->pMixer, "[Recording] Microphone In", AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn);
    693841        if (RT_SUCCESS(rc))
    694             rc = ichac97StreamInit(&pThis->StreamMicIn, AC97SOUNDSOURCE_MC_INDEX);
     842            rc = ichac97StreamCreate(pThis, &pThis->StreamMicIn, AC97SOUNDSOURCE_MC_INDEX);
    695843    }
    696844
     
    700848        rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOut);
    701849        if (RT_SUCCESS(rc))
    702             rc = ichac97StreamInit(&pThis->StreamOut, AC97SOUNDSOURCE_PO_INDEX);
     850            rc = ichac97StreamCreate(pThis, &pThis->StreamOut, AC97SOUNDSOURCE_PO_INDEX);
    703851    }
    704852
     
    727875    LogFlowFuncEnter();
    728876
    729     ichac97DestroyIn(pThis, PDMAUDIORECSOURCE_LINE);
    730     ichac97DestroyIn(pThis, PDMAUDIORECSOURCE_MIC);
    731     ichac97DestroyOut(pThis);
    732 
    733     ichac97StreamDestroy(&pThis->StreamLineIn);
    734     ichac97StreamDestroy(&pThis->StreamMicIn);
    735     ichac97StreamDestroy(&pThis->StreamOut);
     877    ichac97StreamDestroy(pThis, &pThis->StreamLineIn);
     878    ichac97StreamDestroy(pThis, &pThis->StreamMicIn);
     879    ichac97StreamDestroy(pThis, &pThis->StreamOut);
     880}
     881
     882/**
     883 * Writes audio data from a mixer sink into an AC'97 stream's DMA buffer.
     884 *
     885 * @returns IPRT status code.
     886 * @param   pThis               AC'97 state.
     887 * @param   pStream             AC'97 stream to write to.
     888 * @param   pMixSink            Mixer sink to get audio data to write from.
     889 * @param   cbToWrite           Number of bytes to write.
     890 * @param   pcbWritten          Number of bytes written. Optional.
     891 */
     892static int ichac97StreamWrite(PAC97STATE pThis, PAC97STREAM pDstStream, PAUDMIXSINK pSrcMixSink, uint32_t cbToWrite,
     893                              uint32_t *pcbWritten)
     894{
     895    RT_NOREF(pThis);
     896
     897    PRTCIRCBUF pCircBuf = pDstStream->State.pCircBuf;
     898    AssertPtr(pCircBuf);
     899
     900    void *pvDst;
     901    size_t cbDst;
     902
     903    uint32_t cbRead = 0;
     904
     905    RTCircBufAcquireWriteBlock(pCircBuf, cbToWrite, &pvDst, &cbDst);
     906
     907    if (cbDst)
     908    {
     909        int rc2 = AudioMixerSinkRead(pSrcMixSink, AUDMIXOP_COPY, pvDst, (uint32_t)cbDst, &cbRead);
     910        AssertRC(rc2);
     911
     912#ifdef AC97_DEBUG_DUMP_PCM_DATA
     913        RTFILE fh;
     914        RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ichac97StreamWrite.pcm",
     915                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
     916        RTFileWrite(fh, pvDst, cbRead, NULL);
     917        RTFileClose(fh);
     918#endif
     919    }
     920
     921    RTCircBufReleaseWriteBlock(pCircBuf, cbRead);
     922
     923    if (pcbWritten)
     924        *pcbWritten = cbRead;
     925
     926    return VINF_SUCCESS;
     927}
     928
     929/**
     930 * Reads audio data from an AC'97 stream's DMA buffer and writes into a specified mixer sink.
     931 *
     932 * @returns IPRT status code.
     933 * @param   pThis               AC'97 state.
     934 * @param   pSrcStream          AC'97 stream to read audio data from.
     935 * @param   pDstMixSink         Mixer sink to write audio data to.
     936 * @param   cbToRead            Number of bytes to read.
     937 * @param   pcbRead             Number of bytes read. Optional.
     938 */
     939static int ichac97StreamRead(PAC97STATE pThis, PAC97STREAM pSrcStream, PAUDMIXSINK pDstMixSink, uint32_t cbToRead,
     940                             uint32_t *pcbRead)
     941{
     942    RT_NOREF(pThis);
     943
     944    PRTCIRCBUF pCircBuf = pSrcStream->State.pCircBuf;
     945    AssertPtr(pCircBuf);
     946
     947    void *pvSrc;
     948    size_t cbSrc;
     949
     950    uint32_t cbWritten = 0;
     951
     952    RTCircBufAcquireReadBlock(pCircBuf, cbToRead, &pvSrc, &cbSrc);
     953
     954    if (cbSrc)
     955    {
     956#ifdef AC97_DEBUG_DUMP_PCM_DATA
     957        RTFILE fh;
     958        RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97StreamRead.pcm",
     959                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
     960        RTFileWrite(fh, pvSrc, cbSrc, NULL);
     961        RTFileClose(fh);
     962#endif
     963        int rc2 = AudioMixerSinkWrite(pDstMixSink, AUDMIXOP_COPY, pvSrc, (uint32_t)cbSrc, &cbWritten);
     964        AssertRC(rc2);
     965    }
     966
     967    RTCircBufReleaseReadBlock(pCircBuf, cbWritten);
     968
     969    if (pcbRead)
     970        *pcbRead = cbWritten;
     971
     972    return VINF_SUCCESS;
     973}
     974
     975#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     976/**
     977 * Asynchronous I/O thread for an AC'97 stream.
     978 * This will do the heavy lifting work for us as soon as it's getting notified by another thread.
     979 *
     980 * @returns IPRT status code.
     981 * @param   hThreadSelf         Thread handle.
     982 * @param   pvUser              User argument. Must be of type PAC97STREAMTHREADCTX.
     983 */
     984static DECLCALLBACK(int) ichac97StreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser)
     985{
     986    PAC97STREAMTHREADCTX pCtx = (PAC97STREAMTHREADCTX)pvUser;
     987    AssertPtr(pCtx);
     988
     989    PAC97STATE pThis = pCtx->pThis;
     990    AssertPtr(pThis);
     991
     992    PAC97STREAM pStream = pCtx->pStream;
     993    AssertPtr(pStream);
     994
     995    PAC97STREAMSTATEAIO pAIO = &pCtx->pStream->State.AIO;
     996
     997    PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
     998    AssertPtr(pCircBuf);
     999
     1000    PAUDMIXSINK pMixSink = ichac97IndexToSink(pThis, pStream->u8Strm);
     1001    AssertPtr(pMixSink);
     1002
     1003    ASMAtomicXchgBool(&pAIO->fStarted, true);
     1004
     1005    RTThreadUserSignal(hThreadSelf);
     1006
     1007    LogFunc(("[SD%RU8]: Started\n", pStream->u8Strm));
     1008
     1009    for (;;)
     1010    {
     1011        Log2Func(("[SD%RU8]: Waiting ...\n", pStream->u8Strm));
     1012
     1013        int rc2 = RTSemEventWait(pAIO->Event, RT_INDEFINITE_WAIT);
     1014        if (RT_FAILURE(rc2))
     1015            break;
     1016
     1017        if (ASMAtomicReadBool(&pAIO->fShutdown))
     1018            break;
     1019
     1020        size_t cbToProcess = RTCircBufUsed(pCircBuf);
     1021        if (cbToProcess)
     1022        {
     1023            uint32_t cbProcessed = 0;
     1024
     1025            rc2 = RTCritSectEnter(&pAIO->CritSect);
     1026            if (RT_SUCCESS(rc2))
     1027            {
     1028                switch (pStream->u8Strm)
     1029                {
     1030                    case AC97SOUNDSOURCE_PI_INDEX:
     1031                    case AC97SOUNDSOURCE_MC_INDEX:
     1032                        rc2 = ichac97StreamWrite(pThis, pStream, pMixSink, (uint32_t)cbToProcess, &cbProcessed);
     1033                        break;
     1034
     1035                    case AC97SOUNDSOURCE_PO_INDEX:
     1036                        rc2 = ichac97StreamRead(pThis, pStream, pMixSink, (uint32_t)cbToProcess, &cbProcessed);
     1037                        break;
     1038
     1039                    default:
     1040                        AssertFailedStmt(rc2 = VERR_NOT_SUPPORTED);
     1041                        break;
     1042                }
     1043
     1044                if (RT_SUCCESS(rc2))
     1045                    rc2 = AudioMixerSinkUpdate(pMixSink);
     1046
     1047                if (cbProcessed)
     1048                {
     1049                    Assert(cbToProcess >= cbProcessed);
     1050                    cbToProcess -= cbProcessed;
     1051                }
     1052
     1053                int rc3 = RTCritSectLeave(&pAIO->CritSect);
     1054                AssertRC(rc3);
     1055            }
     1056        }
     1057
     1058        AssertRC(rc2);
     1059    }
     1060
     1061    LogFunc(("[SD%RU8]: Ended\n", pStream->u8Strm));
     1062
     1063    ASMAtomicXchgBool(&pAIO->fStarted, false);
     1064
     1065    return VINF_SUCCESS;
     1066}
     1067
     1068/**
     1069 * Lets the stream's async I/O thread know that there is some data to process.
     1070 *
     1071 * @returns IPRT status code.
     1072 * @param   pThis               AC'97 state.
     1073 * @param   pStream             AC'97 stream to notify async I/O thread for.
     1074 */
     1075static int ichac97StreamAsyncIONotify(PAC97STATE pThis, PAC97STREAM pStream)
     1076{
     1077    RT_NOREF(pThis);
     1078
     1079    LogFunc(("[SD%RU8]\n", pStream->u8Strm));
     1080    return RTSemEventSignal(pStream->State.AIO.Event);
     1081}
     1082
     1083static void ichac97StreamAsyncIOLock(PAC97STREAM pStream)
     1084{
     1085    PAC97STREAMSTATEAIO pAIO = &pStream->State.AIO;
     1086
     1087    int rc2 = RTCritSectEnter(&pAIO->CritSect);
     1088    AssertRC(rc2);
     1089}
     1090
     1091static void ichac97StreamAsyncIOUnlock(PAC97STREAM pStream)
     1092{
     1093    PAC97STREAMSTATEAIO pAIO = &pStream->State.AIO;
     1094
     1095    int rc2 = RTCritSectLeave(&pAIO->CritSect);
     1096    AssertRC(rc2);
     1097}
     1098#endif /* VBOX_WITH_AUDIO_AC97_ASYNC_IO*/
     1099
     1100/**
     1101 * Updates an AC'97 stream according to its usage (input / output).
     1102 *
     1103 * For an SDO (output) stream this means reading DMA data from the device to
     1104 * the connected audio sink(s).
     1105 *
     1106 * For an SDI (input) stream this is reading audio data from the connected
     1107 * audio sink(s) and writing it as DMA data to the device.
     1108 *
     1109 * @returns IPRT status code.
     1110 * @param   pThis               AC'97 state.
     1111 * @param   pStream             AC'97 stream to update.
     1112 */
     1113static int ichac97StreamUpdate(PAC97STATE pThis, PAC97STREAM pStream)
     1114{
     1115    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     1116    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
     1117
     1118    PAUDMIXSINK pMixSink = ichac97IndexToSink(pThis, pStream->u8Strm);
     1119    if (!pMixSink)
     1120        return VINF_SUCCESS;
     1121
     1122    if (AudioMixerSinkIsActive(pMixSink) == false)
     1123        return VINF_SUCCESS;
     1124
     1125    PRTCIRCBUF pCircBuf  = pStream->State.pCircBuf;
     1126    AssertPtr(pCircBuf);
     1127
     1128    int rc = VINF_SUCCESS;
     1129
     1130    bool fDone = false;
     1131
     1132    LogFunc(("[SD%RU8] Started\n", pStream->u8Strm));
     1133
     1134    while (!fDone)
     1135    {
     1136        int rc2;
     1137        uint32_t cbProcessed = 0;
     1138
     1139        if (pStream->u8Strm == AC97SOUNDSOURCE_PO_INDEX) /* Output. */
     1140        {
     1141            STAM_PROFILE_START(&pThis->StatOut, a);
     1142
     1143            void *pvDst;
     1144            size_t cbDst;
     1145
     1146            RTCircBufAcquireWriteBlock(pCircBuf, 256 /** @todo */, &pvDst, &cbDst);
     1147
     1148            if (cbDst)
     1149            {
     1150                /* Do one DMA transfer with FIFOS size at a time. */
     1151                rc2 = ichac97DoDMA(pThis, pStream, pvDst, (uint32_t)cbDst, (uint32_t)cbDst /* cbToProcess */, &cbProcessed);
     1152                AssertRC(rc2);
     1153            }
     1154
     1155            RTCircBufReleaseWriteBlock(pCircBuf, cbProcessed);
     1156
     1157            if (cbProcessed)
     1158            {
     1159#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     1160                /* Let the asynchronous thread know that there is some new data to process. */
     1161                ichac97StreamAsyncIONotify(pThis, pStream);
     1162#else
     1163                rc2 = ichac97StreamRead(pThis, pStream, pMixSink, cbProcessed, NULL /* pcbRead */);
     1164                AssertRC(rc2);
     1165#endif
     1166            }
     1167
     1168            if (   !cbProcessed
     1169#ifndef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     1170                && RTCircBufUsed(pCircBuf) == 0
     1171#endif
     1172               )
     1173            {
     1174                fDone = true;
     1175            }
     1176
     1177            STAM_PROFILE_STOP(&pThis->StatOut, a);
     1178        }
     1179        else if (   pStream->u8Strm == AC97SOUNDSOURCE_PI_INDEX  /* Input. */
     1180                 || pStream->u8Strm == AC97SOUNDSOURCE_MC_INDEX) /* Input. */
     1181        {
     1182            STAM_PROFILE_START(&pThis->StatIn, a);
     1183
     1184            void *pvSrc;
     1185            size_t cbSrc;
     1186
     1187            RTCircBufAcquireReadBlock(pCircBuf, 256 /** @todo */, &pvSrc, &cbSrc);
     1188
     1189            if (cbSrc)
     1190            {
     1191                /* Do one DMA transfer with FIFOS size at a time. */
     1192                rc2 = ichac97DoDMA(pThis, pStream, pvSrc, (uint32_t)cbSrc, (uint32_t)cbSrc /* cbToProcess */, &cbProcessed);
     1193                AssertRC(rc2);
     1194            }
     1195
     1196            RTCircBufReleaseReadBlock(pCircBuf, cbProcessed);
     1197
     1198            if (cbProcessed)
     1199            {
     1200#ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     1201                /* Let the asynchronous thread know that there is some new data to process. */
     1202                ichac97StreamAsyncIONotify(pThis, pStream);
     1203#else
     1204                rc2 = ichac97StreamWrite(pThis, pStream, pMixSink, cbProcessed, NULL /* pcbWritten */);
     1205                AssertRC(rc2);
     1206#endif
     1207            }
     1208
     1209            STAM_PROFILE_STOP(&pThis->StatIn, a);
     1210        }
     1211        else
     1212            AssertFailed();
     1213
     1214#ifndef VBOX_WITH_AUDIO_AC97_ASYNC_IO
     1215        rc2 = AudioMixerSinkUpdate(pMixSink);
     1216        AssertRC(rc2);
     1217#endif
     1218        if (fDone)
     1219            break;
     1220    }
     1221
     1222    LogFunc(("[SD%RU8] End\n", pStream->u8Strm));
     1223
     1224    return rc;
    7361225}
    7371226
     
    7631252}
    7641253
    765 static void ichac97DestroyIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource)
    766 {
    767     AssertPtrReturnVoid(pThis);
    768 
    769     LogFlowFuncEnter();
    770 
    771     switch (enmRecSource)
    772     {
    773         case PDMAUDIORECSOURCE_MIC:
    774             AudioMixerSinkDestroy(pThis->pSinkMicIn);
    775             pThis->pSinkMicIn = NULL;
    776             break;
    777 
    778         case PDMAUDIORECSOURCE_LINE:
    779             AudioMixerSinkDestroy(pThis->pSinkLineIn);
    780             pThis->pSinkLineIn = NULL;
    781             break;
    782 
    783         default:
    784             AssertMsgFailed(("Audio source %ld not supported\n", enmRecSource));
    785             return;
    786     }
    787 
    788     PAC97DRIVER pDrv;
    789     RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
    790     {
    791         PAC97INPUTSTREAM pStream;
    792         if (enmRecSource == PDMAUDIORECSOURCE_MIC) /** @todo Refine this once we have more streams. */
    793             pStream = &pDrv->MicIn;
    794         else
    795             pStream = &pDrv->LineIn;
    796 
    797         pStream->pMixStrm = NULL;
    798     }
    799 }
    800 
    801 static void ichac97DestroyOut(PAC97STATE pThis)
    802 {
    803     AssertPtrReturnVoid(pThis);
    804 
    805     LogFlowFuncEnter();
    806 
    807     AudioMixerSinkDestroy(pThis->pSinkOut);
    808     pThis->pSinkOut = NULL;
    809 
    810     PAC97DRIVER pDrv;
    811     RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
    812     {
    813         pDrv->Out.pMixStrm = NULL;
    814     }
    815 }
    816 
    817 static int ichac97CreateIn(PAC97STATE pThis,
    818                            const char *pszName, PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOSTREAMCFG pCfg)
    819 {
    820     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    821     AssertPtrReturn(pszName, VERR_INVALID_POINTER);
    822     AssertPtrReturn(pCfg,    VERR_INVALID_POINTER);
    823 
    824     PAUDMIXSINK pSink;
    825     switch (enmRecSource)
    826     {
    827         case PDMAUDIORECSOURCE_MIC:
    828             pSink = pThis->pSinkMicIn;
    829             break;
    830         case PDMAUDIORECSOURCE_LINE:
    831             pSink = pThis->pSinkLineIn;
    832             break;
    833         default:
    834             AssertMsgFailed(("Audio source %ld not supported\n", enmRecSource));
    835             return VERR_NOT_SUPPORTED;
    836     }
     1254/**
     1255 * Retrieves a specific driver stream of a AC'97 driver.
     1256 *
     1257 * @returns Pointer to driver stream if found, or NULL if not found.
     1258 * @param   pThis               AC'97 state.
     1259 * @param   pDrv                Driver to retrieve driver stream for.
     1260 * @param   enmDir              Stream direction to retrieve.
     1261 * @param   dstSrc              Stream destination / source to retrieve.
     1262 */
     1263static PAC97DRIVERSTREAM ichac97MixerGetDrvStream(PAC97STATE pThis, PAC97DRIVER pDrv,
     1264                                                  PDMAUDIODIR enmDir, PDMAUDIODESTSOURCE dstSrc)
     1265{
     1266    RT_NOREF(pThis);
     1267
     1268    PAC97DRIVERSTREAM pDrvStream = NULL;
     1269
     1270    if (enmDir == PDMAUDIODIR_IN)
     1271    {
     1272        LogFunc(("enmRecSource=%d\n", dstSrc.Source));
     1273
     1274        switch (dstSrc.Source)
     1275        {
     1276            case PDMAUDIORECSOURCE_LINE:
     1277                pDrvStream = &pDrv->LineIn;
     1278                break;
     1279            case PDMAUDIORECSOURCE_MIC:
     1280                pDrvStream = &pDrv->MicIn;
     1281                break;
     1282            default:
     1283                AssertFailed();
     1284                break;
     1285        }
     1286    }
     1287    else if (enmDir == PDMAUDIODIR_OUT)
     1288    {
     1289        LogFunc(("enmPlaybackDest=%d\n", dstSrc.Dest));
     1290
     1291        switch (dstSrc.Dest)
     1292        {
     1293            case PDMAUDIOPLAYBACKDEST_FRONT:
     1294                pDrvStream = &pDrv->Out;
     1295                break;
     1296            default:
     1297                AssertFailed();
     1298                break;
     1299        }
     1300    }
     1301    else
     1302        AssertFailed();
     1303
     1304    return pDrvStream;
     1305}
     1306
     1307/**
     1308 * Adds audio streams for all drivers to a specific mixer sink.
     1309 *
     1310 * @returns IPRT status code.
     1311 * @param   pThis               AC'97 state.
     1312 * @param   pMixSink            Mixer sink to add stream to.
     1313 * @param   pCfg                Stream configuration to use.
     1314 */
     1315static int ichac97MixerAddDrvStreams(PAC97STATE pThis, PAUDMIXSINK pMixSink, PPDMAUDIOSTREAMCFG pCfg)
     1316{
     1317    AssertPtrReturn(pThis,    VERR_INVALID_POINTER);
     1318    AssertPtrReturn(pMixSink, VERR_INVALID_POINTER);
     1319    AssertPtrReturn(pCfg,     VERR_INVALID_POINTER);
    8371320
    8381321    /* Update the sink's format. */
     
    8401323    int rc = DrvAudioHlpStreamCfgToProps(pCfg, &PCMProps);
    8411324    if (RT_SUCCESS(rc))
    842         rc = AudioMixerSinkSetFormat(pSink, &PCMProps);
     1325        rc = AudioMixerSinkSetFormat(pMixSink, &PCMProps);
    8431326
    8441327    if (RT_FAILURE(rc))
     
    8481331    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
    8491332    {
    850         if (!RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "[LUN#%RU8] %s", pDrv->uLUN, pszName))
    851         {
     1333        PPDMAUDIOSTREAMCFG pStreamCfg = (PPDMAUDIOSTREAMCFG)RTMemDup(pCfg, sizeof(PDMAUDIOSTREAMCFG));
     1334        if (!pStreamCfg)
     1335        {
     1336            rc = VERR_NO_MEMORY;
     1337            break;
     1338        }
     1339
     1340        if (!RTStrPrintf(pStreamCfg->szName, sizeof(pStreamCfg->szName), "[LUN#%RU8] %s", pDrv->uLUN, pCfg->szName))
     1341        {
     1342            RTMemFree(pStreamCfg);
     1343
    8521344            rc = VERR_BUFFER_OVERFLOW;
    8531345            break;
    8541346        }
    8551347
    856         PAC97INPUTSTREAM pStream;
    857         if (enmRecSource == PDMAUDIORECSOURCE_MIC) /** @todo Refine this once we have more streams. */
    858             pStream = &pDrv->MicIn;
    859         else
    860             pStream = &pDrv->LineIn;
    861 
    862         AudioMixerSinkRemoveStream(pSink, pStream->pMixStrm);
    863 
    864         AudioMixerStreamDestroy(pStream->pMixStrm);
    865         pStream->pMixStrm = NULL;
    866 
    867         int rc2 = AudioMixerSinkCreateStream(pSink, pDrv->pConnector, pCfg, 0 /* fFlags */ , &pStream->pMixStrm);
    868         if (RT_SUCCESS(rc2))
    869         {
    870             rc2 = AudioMixerSinkAddStream(pSink, pStream->pMixStrm);
    871             LogFlowFunc(("LUN#%RU8: Created input \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2));
     1348        LogFunc(("%s\n", pStreamCfg->szName));
     1349
     1350        int rc2 = VINF_SUCCESS;
     1351
     1352        PAC97DRIVERSTREAM pDrvStream = ichac97MixerGetDrvStream(pThis, pDrv, pStreamCfg->enmDir, pStreamCfg->DestSource);
     1353        if (pDrvStream)
     1354        {
     1355            AssertMsg(pDrvStream->pMixStrm == NULL, ("[LUN#%RU8] Driver stream already present when it must not\n", pDrv->uLUN));
     1356
     1357            PAUDMIXSTREAM pMixStrm;
     1358            rc2 = AudioMixerSinkCreateStream(pMixSink, pDrv->pConnector, pStreamCfg, 0 /* fFlags */, &pMixStrm);
     1359            if (RT_SUCCESS(rc2))
     1360            {
     1361                rc2 = AudioMixerSinkAddStream(pMixSink, pMixStrm);
     1362                LogFlowFunc(("LUN#%RU8: Created stream \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2));
     1363            }
     1364
     1365            if (RT_SUCCESS(rc2))
     1366                pDrvStream->pMixStrm = pMixStrm;
    8721367        }
    8731368
    8741369        if (RT_SUCCESS(rc))
    8751370            rc = rc2;
     1371
     1372        if (pStreamCfg)
     1373        {
     1374            RTMemFree(pStreamCfg);
     1375            pStreamCfg = NULL;
     1376        }
    8761377    }
    8771378
     
    8801381}
    8811382
    882 static int ichac97CreateOut(PAC97STATE pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
    883 {
    884     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    885     AssertPtrReturn(pszName, VERR_INVALID_POINTER);
    886     AssertPtrReturn(pCfg,    VERR_INVALID_POINTER);
    887 
    888     LogFunc(("%s\n", pszName));
    889 
    890     /* Update the sink's format. */
    891     PDMAUDIOPCMPROPS PCMProps;
    892     int rc = DrvAudioHlpStreamCfgToProps(pCfg, &PCMProps);
    893     if (RT_SUCCESS(rc))
    894         rc = AudioMixerSinkSetFormat(pThis->pSinkOut, &PCMProps);
    895 
    896     if (RT_FAILURE(rc))
    897         return rc;
     1383/**
     1384 * Removes specific audio streams for all drivers.
     1385 *
     1386 * @param   pThis               AC'97 state.
     1387 * @param   pMixSink            Mixer sink to remove audio streams from.
     1388 * @param   enmDir              Stream direction to remove.
     1389 * @param   dstSrc              Stream destination / source to remove.
     1390 */
     1391static void ichac97MixerRemoveDrvStreams(PAC97STATE pThis, PAUDMIXSINK pMixSink,
     1392                                         PDMAUDIODIR enmDir, PDMAUDIODESTSOURCE dstSrc)
     1393{
     1394    AssertPtrReturnVoid(pThis);
     1395    AssertPtrReturnVoid(pMixSink);
    8981396
    8991397    PAC97DRIVER pDrv;
    9001398    RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
    9011399    {
    902         if (!RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "[LUN#%RU8] %s (%RU32Hz, %RU8 %s)",
    903                          pDrv->uLUN, pszName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel"))
    904         {
    905             rc = VERR_BUFFER_OVERFLOW;
    906             break;
    907         }
    908 
    909         AudioMixerSinkRemoveStream(pThis->pSinkOut, pDrv->Out.pMixStrm);
    910 
    911         AudioMixerStreamDestroy(pDrv->Out.pMixStrm);
    912         pDrv->Out.pMixStrm = NULL;
    913 
    914         int rc2 = AudioMixerSinkCreateStream(pThis->pSinkOut, pDrv->pConnector, pCfg, 0 /* fFlags */, &pDrv->Out.pMixStrm);
    915         if (RT_SUCCESS(rc2))
    916         {
    917             rc2 = AudioMixerSinkAddStream(pThis->pSinkOut, pDrv->Out.pMixStrm);
    918             LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2));
    919         }
    920 
    921         if (RT_SUCCESS(rc))
    922             rc = rc2;
    923     }
    924 
    925     LogFlowFuncLeaveRC(rc);
    926     return rc;
    927 }
    928 
    929 /**
    930  * Opens an AC'97 stream, extended version.
     1400        PAC97DRIVERSTREAM pDrvStream = ichac97MixerGetDrvStream(pThis, pDrv, enmDir, dstSrc);
     1401        if (pDrvStream)
     1402        {
     1403            if (pDrvStream->pMixStrm)
     1404            {
     1405                AudioMixerSinkRemoveStream(pMixSink, pDrvStream->pMixStrm);
     1406
     1407                AudioMixerStreamDestroy(pDrvStream->pMixStrm);
     1408                pDrvStream->pMixStrm = NULL;
     1409            }
     1410        }
     1411    }
     1412}
     1413
     1414/**
     1415 * Opens an AC'97 stream with its current mixer settings.
    9311416 *
    932  * @returns IPRT status code.
    933  * @param   pThis               AC'97 device state.
    934  * @param   pStream             Stream to initialize.
    935  * @param   pCfg                Audio stream configuration to initialize the stream with.
    936  */
    937 static int ichac97StreamOpenEx(PAC97STATE pThis, PAC97STREAM pStream, PPDMAUDIOSTREAMCFG pCfg)
    938 {
    939     AssertPtrReturn(pThis,             VERR_INVALID_POINTER);
    940     AssertPtrReturn(pStream,           VERR_INVALID_POINTER);
    941     AssertPtrReturn(pCfg,              VERR_INVALID_POINTER);
    942 
    943     LogFunc(("[SD%RU8] pCfg=%p\n", pStream->u8Strm, pCfg));
    944 
    945     int rc;
    946     switch (pStream->u8Strm)
    947     {
    948         case AC97SOUNDSOURCE_PI_INDEX:
    949             rc = ichac97CreateIn(pThis, "ac97.pi", PDMAUDIORECSOURCE_LINE, pCfg);
    950             break;
    951 
    952         case AC97SOUNDSOURCE_MC_INDEX:
    953             rc = ichac97CreateIn(pThis, "ac97.mc", PDMAUDIORECSOURCE_MIC, pCfg);
    954             break;
    955 
    956         case AC97SOUNDSOURCE_PO_INDEX:
    957             rc = ichac97CreateOut(pThis, "ac97.po", pCfg);
    958             break;
    959 
    960         default:
    961             AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
    962             break;
    963     }
    964 
    965     if (RT_FAILURE(rc))
    966         LogRel2(("AC97: Error opening stream #%RU8, rc=%Rrc\n", pStream->u8Strm, rc));
    967 
    968     LogFlowFuncLeaveRC(rc);
    969     return rc;
    970 }
    971 
    972 /**
    973  * Opens an AC'97 stream.
    9741417 * This will open an AC'97 stream with 2 (stereo) channels, 16-bit samples and
    9751418 * the last set sample rate in the AC'97 mixer for this stream.
    9761419 *
    9771420 * @returns IPRT status code.
    978  * @param   pThis               AC'97 device state.
    979  * @param   pStream             Stream to initialize.
     1421 * @param   pThis               AC'97 state.
     1422 * @param   pStream             AC'97 Stream to open.
    9801423 */
    9811424static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream)
     
    9881431    RT_ZERO(streamCfg);
    9891432
     1433    PAUDMIXSINK pMixSink = NULL;
     1434
    9901435    switch (pStream->u8Strm)
    9911436    {
    9921437        case AC97SOUNDSOURCE_PI_INDEX:
     1438        {
    9931439            streamCfg.uHz               = ichac97MixerGet(pThis, AC97_PCM_LR_ADC_Rate);
    9941440            streamCfg.enmDir            = PDMAUDIODIR_IN;
    9951441            streamCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
     1442
     1443            RTStrPrintf2(streamCfg.szName, sizeof(streamCfg.szName), "Line-In");
     1444
     1445            pMixSink                    = pThis->pSinkLineIn;
    9961446            break;
     1447        }
    9971448
    9981449        case AC97SOUNDSOURCE_MC_INDEX:
     1450        {
    9991451            streamCfg.uHz               = ichac97MixerGet(pThis, AC97_MIC_ADC_Rate);
    10001452            streamCfg.enmDir            = PDMAUDIODIR_IN;
    10011453            streamCfg.DestSource.Source = PDMAUDIORECSOURCE_MIC;
     1454
     1455            RTStrPrintf2(streamCfg.szName, sizeof(streamCfg.szName), "Mic-In");
     1456
     1457            pMixSink                    = pThis->pSinkMicIn;
    10021458            break;
     1459        }
    10031460
    10041461        case AC97SOUNDSOURCE_PO_INDEX:
     1462        {
    10051463            streamCfg.uHz               = ichac97MixerGet(pThis, AC97_PCM_Front_DAC_Rate);
    10061464            streamCfg.enmDir            = PDMAUDIODIR_OUT;
    10071465            streamCfg.DestSource.Dest   = PDMAUDIOPLAYBACKDEST_FRONT;
     1466
     1467            RTStrPrintf2(streamCfg.szName, sizeof(streamCfg.szName), "Output");
     1468
     1469            pMixSink                    = pThis->pSinkOut;
    10081470            break;
     1471        }
    10091472
    10101473        default:
     
    10151478    if (RT_SUCCESS(rc))
    10161479    {
    1017         if (streamCfg.uHz)
     1480        if (streamCfg.uHz) /* Some valid rate set in the AC'97 mixer? */
    10181481        {
    10191482            streamCfg.cChannels     = 2;
     
    10211484            streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
    10221485
    1023             rc = ichac97StreamOpenEx(pThis, pStream, &streamCfg);
    1024         }
    1025         else
    1026             rc = VERR_INVALID_PARAMETER;
     1486            ichac97MixerRemoveDrvStreams(pThis, pMixSink, streamCfg.enmDir, streamCfg.DestSource);
     1487
     1488            rc = ichac97MixerAddDrvStreams(pThis, pMixSink, &streamCfg);
     1489        }
    10271490    }
    10281491
     
    10311494}
    10321495
    1033 static void ichac97StreamClose(PAC97STREAM pStream)
    1034 {
     1496/**
     1497 * Closes an AC'97 stream.
     1498 *
     1499 * @returns IPRT status code.
     1500 * @param   pThis               AC'97 state.
     1501 * @param   pStream             AC'97 stream to close.
     1502 */
     1503static int ichac97StreamClose(PAC97STATE pThis, PAC97STREAM pStream)
     1504{
     1505    RT_NOREF(pThis);
    10351506    RT_NOREF(pStream);
    10361507
    10371508    LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
    1038 }
    1039 
    1040 /**
    1041  * Re-opens an AC'97 stream on the backend side with the current AC'97 mixer
    1042  * settings for this stream.
     1509
     1510    return VINF_SUCCESS;
     1511}
     1512
     1513/**
     1514 * Re-opens (that is, closes and opens again) an AC'97 stream on the backend
     1515 * side with the current AC'97 mixer settings for this stream.
    10431516 *
    10441517 * @returns IPRT status code.
    10451518 * @param   pThis               AC'97 device state.
    1046  * @param   pStream             Stream to re-open.
     1519 * @param   pStream             AC'97 stream to re-open.
    10471520 */
    10481521static int ichac97StreamReOpen(PAC97STATE pThis, PAC97STREAM pStream)
     
    10501523    LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
    10511524
    1052     ichac97StreamClose(pStream);
    1053 
    1054     return ichac97StreamOpen(pThis, pStream);
    1055 }
    1056 
    1057 static void ichac97StreamReset(PAC97STATE pThis, PAC97STREAM pStrm)
     1525    int rc = ichac97StreamClose(pThis, pStream);
     1526    if (RT_SUCCESS(rc))
     1527        rc = ichac97StreamOpen(pThis, pStream);
     1528
     1529    return rc;
     1530}
     1531
     1532/**
     1533 * Resets an AC'97 stream.
     1534 *
     1535 * @returns IPRT status code.
     1536 * @param   pThis               AC'97 state.
     1537 * @param   pStream             AC'97 stream to reset.
     1538 * @remark
     1539 */
     1540static void ichac97StreamReset(PAC97STATE pThis, PAC97STREAM pStream)
    10581541{
    10591542    AssertPtrReturnVoid(pThis);
    1060     AssertPtrReturnVoid(pStrm);
    1061 
    1062     LogFlowFunc(("[SD%RU8]\n", pStrm->u8Strm));
    1063 
    1064     if (pStrm->State.au8FIFOW)
    1065     {
    1066         Assert(pStrm->State.cbFIFOW);
    1067         RT_BZERO(pStrm->State.au8FIFOW, pStrm->State.cbFIFOW);
    1068     }
    1069 
    1070     pStrm->State.offFIFOW = 0;
     1543    AssertPtrReturnVoid(pStream);
     1544
     1545    LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
     1546
     1547    if (pStream->State.pCircBuf)
     1548        RTCircBufReset(pStream->State.pCircBuf);
    10711549}
    10721550
     
    11911669        case PDMAUDIORECSOURCE_VIDEO:   return AC97_REC_VIDEO;
    11921670        case PDMAUDIORECSOURCE_AUX:     return AC97_REC_AUX;
    1193         case PDMAUDIORECSOURCE_LINE: return AC97_REC_LINE_IN;
     1671        case PDMAUDIORECSOURCE_LINE:    return AC97_REC_LINE_IN;
    11941672        case PDMAUDIORECSOURCE_PHONE:   return AC97_REC_PHONE;
    11951673        default:
     
    12731751}
    12741752
    1275 /**
    1276  * Writes data from the device to the host backends.
    1277  *
    1278  * @return  IPRT status code.
    1279  * @param   pThis
    1280  * @param   pStream
    1281  * @param   cbMax
    1282  * @param   pcbWritten
    1283  */
    1284 static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
    1285 {
    1286     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    1287     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    1288     AssertReturn(cbToWrite,  VERR_INVALID_PARAMETER);
    1289     /* pcbWritten is optional. */
    1290 
    1291     PPDMDEVINS  pDevIns = ICHAC97STATE_2_DEVINS(pThis);
    1292     PAC97BMREGS pRegs   = &pStream->Regs;
    1293 
    1294     uint32_t    uAddr   = pRegs->bd.addr;
    1295 
    1296     uint32_t    cbWrittenTotal = 0;
    1297 
    1298     Log3Func(("PICB=%RU16, cbToWrite=%RU32\n", pRegs->picb, cbToWrite));
    1299 
    1300     uint32_t cbLeft = RT_MIN((uint32_t)(pRegs->picb << 1), cbToWrite); /** @todo r=andy Assumes 16bit sample size. */
    1301     if (!cbLeft)
    1302     {
    1303         if (pcbWritten)
    1304             *pcbWritten = 0;
    1305         return VINF_EOF;
    1306     }
    1307 
    1308     int rc = VINF_SUCCESS;
    1309 
    1310     Assert(pStream->State.offFIFOW <= pStream->State.cbFIFOW);
    1311     uint32_t  cbFIFOW  = pStream->State.cbFIFOW - pStream->State.offFIFOW;
    1312     uint8_t  *pu8FIFOW = &pStream->State.au8FIFOW[pStream->State.offFIFOW];
    1313 
    1314     uint32_t cbWritten = 0;
    1315 
    1316     while (cbLeft)
    1317     {
    1318         uint32_t cbToRead = RT_MIN(cbLeft, cbFIFOW);
    1319 
    1320         PDMDevHlpPhysRead(pDevIns, uAddr, pu8FIFOW, cbToRead); /** @todo r=andy Check rc? */
    1321 
    1322 #ifdef AC97_DEBUG_DUMP_PCM_DATA
    1323         RTFILE fh;
    1324         RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97WriteAudio.pcm",
    1325                    RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
    1326         RTFileWrite(fh, pu8FIFOW, cbToRead, NULL);
    1327         RTFileClose(fh);
    1328 #endif
    1329         /*
    1330          * Write data to the mixer sink.
    1331          */
    1332         rc = AudioMixerSinkWrite(pThis->pSinkOut, AUDMIXOP_COPY, pu8FIFOW, cbToRead, &cbWritten);
    1333         if (RT_FAILURE(rc))
    1334             break;
    1335 
    1336         /* Advance. */
    1337         Assert(cbLeft >= cbWritten);
    1338         cbLeft         -= cbWritten;
    1339         cbWrittenTotal += cbWritten;
    1340         uAddr          += cbWritten;
    1341         Assert(cbWrittenTotal <= cbToWrite);
    1342 
    1343         LogFlowFunc(("%RU32 / %RU32\n", cbWrittenTotal, cbToWrite));
    1344     }
    1345 
    1346     /* Set new buffer descriptor address. */
    1347     pRegs->bd.addr = uAddr;
    1348 
    1349     if (RT_SUCCESS(rc))
    1350     {
    1351         if (!cbLeft) /* All data written? */
    1352         {
    1353             if (cbWritten < 4)
    1354             {
    1355                 AssertMsgFailed(("Unable to save last written sample, cbWritten < 4 (is %RU32)\n", cbWritten));
    1356                 pThis->last_samp = 0;
    1357             }
    1358             else
    1359                 pThis->last_samp = *(uint32_t *)&pStream->State.au8FIFOW[pStream->State.offFIFOW + cbWritten - 4];
    1360         }
    1361 
    1362         if (pcbWritten)
    1363             *pcbWritten = cbWrittenTotal;
    1364     }
    1365 
    1366     if (RT_FAILURE(rc))
    1367         LogFlowFunc(("Failed with %Rrc\n", rc));
    1368 
    1369     return rc;
    1370 }
    1371 
    13721753static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
    13731754{
     1755return;
     1756
    13741757    LogFlowFunc(("cbElapsed=%RU32\n", cbElapsed));
    13751758
     
    14091792}
    14101793
    1411 static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)
    1412 {
    1413     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    1414     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    1415     AssertReturn(cbToRead,   VERR_INVALID_PARAMETER);
    1416     /* pcbRead is optional. */
    1417 
    1418     PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
    1419     PAC97BMREGS pRegs  = &pStream->Regs;
    1420 
    1421     /* Select audio sink to process. */
    1422     AssertMsg(pStream->u8Strm != AC97SOUNDSOURCE_PO_INDEX, ("Can't read from output\n"));
    1423     PAUDMIXSINK pSink = pStream->u8Strm == AC97SOUNDSOURCE_MC_INDEX ? pThis->pSinkMicIn : pThis->pSinkLineIn;
    1424     AssertPtr(pSink);
    1425 
    1426     uint32_t cbRead   = 0;
    1427 
    1428     cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1),
    1429                       RT_MIN(pStream->State.cbFIFOW, cbToRead)); /** @todo r=andy Assumes 16bit samples. */
    1430 
    1431     if (!cbToRead)
    1432     {
    1433         if (pcbRead)
    1434             *pcbRead = 0;
    1435         return VINF_EOF;
    1436     }
    1437 
    1438     int rc;
    1439 
    1440     rc = AudioMixerSinkRead(pSink, AUDMIXOP_BLEND, &pStream->State.au8FIFOW[pStream->State.offFIFOW], cbToRead, &cbRead);
    1441     if (   RT_SUCCESS(rc)
    1442         && cbRead)
    1443     {
    1444         PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, &pStream->State.au8FIFOW[pStream->State.offFIFOW], cbRead);
    1445         pRegs->bd.addr += cbRead;
    1446     }
    1447 
    1448     if (RT_SUCCESS(rc))
    1449     {
    1450         if (!cbRead)
    1451             rc = VINF_EOF;
    1452 
    1453         if (pcbRead)
    1454             *pcbRead = cbRead;
    1455     }
    1456 
    1457     return rc;
    1458 }
    1459 
    14601794#ifndef VBOX_WITH_AUDIO_AC97_CALLBACKS
    1461 
    14621795static void ichac97TimerMaybeStart(PAC97STATE pThis)
    14631796{
     
    14681801        return;
    14691802
    1470     if (ASMAtomicReadBool(&pThis->fTimerActive) == true) /* Alredy started? */
     1803    if (ASMAtomicReadBool(&pThis->fTimerActive) == true) /* Already started? */
    14711804        return;
    14721805
    1473     LogFlowFunc(("Starting timer\n"));
     1806    LogRel2(("AC97: Starting transfers\n"));
    14741807
    14751808    /* Set timer flag. */
     
    14791812    pThis->uTimerTS = TMTimerGet(pThis->pTimer);
    14801813
    1481     /* Fire off timer. */
    1482     TMTimerSet(pThis->pTimer, 0 /* u64Expire */);
     1814    /* Start transfers. */
     1815    ichac97DoTransfers(pThis);
    14831816}
    14841817
     
    14941827        return;
    14951828
    1496     LogFlowFunc(("Stopping timer\n"));
     1829    LogRel2(("AC97: Stopping transfers\n"));
    14971830
    14981831    /* Set timer flag. */
     
    15001833}
    15011834
     1835static void ichac97DoTransfers(PAC97STATE pThis)
     1836{
     1837    AssertPtrReturnVoid(pThis);
     1838
     1839    STAM_PROFILE_START(&pThis->StatTimer, a);
     1840
     1841    uint64_t cTicksNow = TMTimerGet(pThis->pTimer);
     1842
     1843    /* Update current time timestamp. */
     1844    pThis->uTimerTS = cTicksNow;
     1845
     1846    /* Flag indicating whether to kick the timer again for the next DMA transfer or sink processing. */
     1847    bool fKickTimer = false;
     1848
     1849    ichac97StreamUpdate(pThis, &pThis->StreamLineIn);
     1850    ichac97StreamUpdate(pThis, &pThis->StreamMicIn);
     1851    ichac97StreamUpdate(pThis, &pThis->StreamOut);
     1852
     1853    /* Do we need to kick the timer again? */
     1854    if (   AudioMixerSinkIsActive(ichac97IndexToSink(pThis, pThis->StreamLineIn.u8Strm))
     1855        || AudioMixerSinkIsActive(ichac97IndexToSink(pThis, pThis->StreamMicIn.u8Strm))
     1856        || AudioMixerSinkIsActive(ichac97IndexToSink(pThis, pThis->StreamOut.u8Strm)))
     1857    {
     1858        fKickTimer = true;
     1859    }
     1860
     1861    if (   ASMAtomicReadBool(&pThis->fTimerActive)
     1862        || fKickTimer)
     1863    {
     1864        /* Kick the timer again. */
     1865        uint64_t cTicks = pThis->cTimerTicks;
     1866        /** @todo adjust cTicks down by now much cbOutMin represents. */
     1867        TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
     1868    }
     1869    else
     1870        LogRel2(("AC97: Stopped transfers\n"));
     1871
     1872    STAM_PROFILE_STOP(&pThis->StatTimer, a);
     1873}
     1874#endif /* !VBOX_WITH_AUDIO_AC97_CALLBACKS */
     1875
    15021876static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
    15031877{
    1504     RT_NOREF(pDevIns);
     1878    RT_NOREF(pDevIns, pTimer);
     1879
    15051880    PAC97STATE pThis = (PAC97STATE)pvUser;
    15061881    Assert(pThis == PDMINS_2_DATA(pDevIns, PAC97STATE));
    15071882    AssertPtr(pThis);
    15081883
    1509     int rc = RTCritSectEnter(&pThis->csTimer);
    1510     if (RT_SUCCESS(rc))
    1511     {
    1512         STAM_PROFILE_START(&pThis->StatTimer, a);
    1513 
    1514         uint64_t cTicksNow = TMTimerGet(pTimer);
    1515 
    1516         /* Update current time timestamp. */
    1517         pThis->uTimerTS = cTicksNow;
    1518 
    1519         /* Flag indicating whether to kick the timer again for the next DMA transfer or sink processing. */
    1520         bool fKickTimer = false;
    1521 
    1522         uint32_t cbToProcess;
    1523 
    1524         rc = AudioMixerSinkUpdate(pThis->pSinkLineIn);
    1525         if (RT_SUCCESS(rc))
    1526         {
    1527             cbToProcess = AudioMixerSinkGetReadable(pThis->pSinkLineIn);
    1528             if (cbToProcess)
    1529                 rc = ichac97TransferAudio(pThis, &pThis->StreamLineIn, cbToProcess, NULL /* pcbProcessed */);
    1530 
    1531             if (AudioMixerSinkGetStatus(pThis->pSinkLineIn) & AUDMIXSINK_STS_DIRTY)
    1532                 fKickTimer = true;
    1533         }
    1534 
    1535         rc = AudioMixerSinkUpdate(pThis->pSinkMicIn);
    1536         if (RT_SUCCESS(rc))
    1537         {
    1538             cbToProcess = AudioMixerSinkGetReadable(pThis->pSinkMicIn);
    1539             if (cbToProcess)
    1540                 rc = ichac97TransferAudio(pThis, &pThis->StreamMicIn, cbToProcess, NULL /* pcbProcessed */);
    1541 
    1542             if (AudioMixerSinkGetStatus(pThis->pSinkMicIn) & AUDMIXSINK_STS_DIRTY)
    1543                 fKickTimer = true;
    1544         }
    1545 
    1546         rc = AudioMixerSinkUpdate(pThis->pSinkOut);
    1547         if (RT_SUCCESS(rc))
    1548         {
    1549             cbToProcess = AudioMixerSinkGetWritable(pThis->pSinkOut);
    1550             if (cbToProcess)
    1551                 rc = ichac97TransferAudio(pThis, &pThis->StreamOut, cbToProcess, NULL /* pcbProcessed */);
    1552 
    1553             if (AudioMixerSinkGetStatus(pThis->pSinkOut) & AUDMIXSINK_STS_DIRTY)
    1554                 fKickTimer = true;
    1555         }
    1556 
    1557         if (fKickTimer)
    1558         {
    1559             /* Kick the timer again. */
    1560             uint64_t cTicks = pThis->cTimerTicks;
    1561             /** @todo adjust cTicks down by now much cbOutMin represents. */
    1562             TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
    1563         }
    1564         else
    1565         {
    1566             LogFunc(("Stopping timer\n"));
    1567             LogRel3(("AC97: Stopping timer\n"));
    1568         }
    1569 
    1570         STAM_PROFILE_STOP(&pThis->StatTimer, a);
    1571 
    1572         int rc2 = RTCritSectLeave(&pThis->csTimer);
    1573         if (RT_SUCCESS(rc))
    1574             rc2 = rc;
    1575     }
    1576 }
    1577 #endif /* !VBOX_WITH_AUDIO_AC97_CALLBACKS */
    1578 
    1579 static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
     1884    ichac97DoTransfers(pThis);
     1885}
     1886
     1887/**
     1888 * Does a single DMA transfer for a specific AC'97 stream.
     1889 * This either can be a read or write operation, depending on the AC'97 stream.
     1890 *
     1891 * @returns IPRT status code.
     1892 * @param   pThis               AC'97 state.
     1893 * @param   pStream             AC'97 stream to do the DMA transfer for.
     1894 * @param   pvBuf               Pointer to buffer data to write data to / read data from.
     1895 * @param   cbBuf               Size of buffer (in bytes).
     1896 * @param   cbToProcess         Size (in bytes) to transfer (read/write).
     1897 * @param   pcbProcessed        Size (in bytes) transferred (read/written). Optional.
     1898 */
     1899static int ichac97DoDMA(PAC97STATE pThis, PAC97STREAM pStream, void *pvBuf, uint32_t cbBuf,
     1900                        uint32_t cbToProcess, uint32_t *pcbProcessed)
    15801901{
    15811902    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
    15821903    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    15831904    /* pcbProcessed is optional. */
    1584 
    1585     int rc = RTCritSectEnter(&pStream->CritSect);
    1586     if (RT_FAILURE(rc))
    1587         return rc;
    1588 
    1589     LogFunc(("[SD%RU8] cbToProcess=%RU32\n", pStream->u8Strm, cbToProcess));
    15901905
    15911906    PAC97BMREGS pRegs = &pStream->Regs;
     
    16091924            *pcbProcessed = 0;
    16101925
    1611         Log3Func(("[SD%RU8] Halted\n", pStream->u8Strm));
    1612 
    1613         rc = RTCritSectLeave(&pStream->CritSect);
    1614         AssertRC(rc);
    1615 
    16161926        return VINF_SUCCESS;
    16171927    }
     
    16251935            *pcbProcessed = 0;
    16261936
    1627         rc = RTCritSectLeave(&pStream->CritSect);
    1628         AssertRC(rc);
    1629 
    16301937        return VINF_SUCCESS;
    16311938    }
    16321939
    1633     uint32_t cbLeft  = RT_MIN((uint32_t)(pRegs->picb << 1), cbToProcess);
     1940    uint32_t cbLeft  = RT_MIN((uint32_t)(pRegs->picb << 1), RT_MIN(cbToProcess, cbBuf));
    16341941    uint32_t cbTotal = 0;
    1635 
    1636     Log3Func(("[SD%RU8] cbLeft=%RU32\n", pStream->u8Strm, cbLeft));
     1942    uint32_t cbChunk;
     1943
     1944    int rc = VINF_SUCCESS;
     1945
     1946    Log3Func(("[SD%RU8] cbToProcess=%RU32, cbLeft=%RU32\n", pStream->u8Strm, cbToProcess, cbLeft));
    16371947
    16381948    while (cbLeft)
     
    16401950        if (!pRegs->bd_valid)
    16411951        {
    1642             LogFlowFunc(("Invalid buffer descriptor, fetching next one ...\n"));
     1952            Log3Func(("Invalid buffer descriptor, fetching next one ...\n"));
    16431953            ichac97StreamFetchBDLE(pThis, pStream);
    16441954        }
     
    16461956        if (!pRegs->picb) /* Got a new buffer descriptor, that is, the position is 0? */
    16471957        {
    1648             LogFlowFunc(("Fresh buffer descriptor %RU8 is empty, addr=%#x, len=%#x, skipping\n",
    1649                          pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len));
     1958            Log3Func(("Fresh buffer descriptor %RU8 is empty, addr=%#x, len=%#x, skipping\n",
     1959                      pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len));
    16501960            if (pRegs->civ == pRegs->lvi)
    16511961            {
     
    16651975        }
    16661976
    1667         uint32_t cbToTransfer, cbTransferred;
     1977        cbChunk = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */
     1978        Assert(cbChunk);
     1979
    16681980        switch (pStream->u8Strm)
    16691981        {
    1670             case AC97SOUNDSOURCE_PO_INDEX:
     1982            case AC97SOUNDSOURCE_PO_INDEX: /* Output */
    16711983            {
    1672                 cbToTransfer = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */
    1673 
    1674                 rc = ichac97WriteAudio(pThis, pStream, cbToTransfer, &cbTransferred);
    1675                 if (   RT_SUCCESS(rc)
    1676                     && cbTransferred)
    1677                 {
    1678                     cbTotal     += cbTransferred;
    1679                     Assert(cbLeft >= cbTransferred);
    1680                     cbLeft      -= cbTransferred;
    1681                     Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
    1682                     pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
    1683                 }
     1984                PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pRegs->bd.addr,
     1985                                  (uint8_t *)pvBuf + cbTotal, cbChunk);
    16841986                break;
    16851987            }
    16861988
    1687             case AC97SOUNDSOURCE_PI_INDEX:
    1688             case AC97SOUNDSOURCE_MC_INDEX:
     1989            case AC97SOUNDSOURCE_PI_INDEX: /* Input */
     1990            case AC97SOUNDSOURCE_MC_INDEX: /* Input */
    16891991            {
    1690                 cbToTransfer = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */
    1691 
    1692                 rc = ichac97ReadAudio(pThis, pStream, cbToTransfer, &cbTransferred);
    1693                 if (   RT_SUCCESS(rc)
    1694                     && cbTransferred)
    1695                 {
    1696                     cbTotal     += cbTransferred;
    1697                     Assert(cbLeft >= cbTransferred);
    1698                     cbLeft      -= cbTransferred;
    1699                     Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
    1700                     pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
    1701                 }
     1992                PDMDevHlpPhysWrite(pThis->CTX_SUFF(pDevIns), pRegs->bd.addr,
     1993                                   (uint8_t *)pvBuf + cbTotal, cbChunk);
    17021994                break;
    17031995            }
     
    17092001        }
    17102002
    1711         LogFlowFunc(("[SD%RU8]: %RU32 / %RU32, rc=%Rrc\n", pStream->u8Strm, cbTotal, cbToProcess, rc));
     2003        if (RT_FAILURE(rc))
     2004            break;
     2005
     2006#ifdef AC97_DEBUG_DUMP_PCM_DATA
     2007        RTFILE fh;
     2008        RTFileOpen(&fh,
     2009                     pStream->u8Strm == AC97SOUNDSOURCE_PO_INDEX
     2010                   ? AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97DMARead.pcm" : AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97DMAWrite.pcm",
     2011                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
     2012        RTFileWrite(fh, (uint8_t *)pvBuf + cbTotal, cbChunk, NULL);
     2013        RTFileClose(fh);
     2014#endif
     2015
     2016        if (cbChunk)
     2017        {
     2018            cbTotal     += cbChunk;
     2019            Assert(cbLeft >= cbChunk);
     2020            cbLeft      -= cbChunk;
     2021            Assert((cbChunk & 1) == 0); /* Else the following shift won't work */
     2022
     2023            pRegs->picb    -= (cbChunk >> 1); /** @todo r=andy Assumes 16bit samples. */
     2024            pRegs->bd.addr += cbChunk;
     2025        }
     2026
     2027        LogFlowFunc(("[SD%RU8]: cbChunk=%RU32, cbLeft=%RU32, cbTotal=%RU32, rc=%Rrc\n",
     2028                     pStream->u8Strm, cbChunk, cbLeft, cbTotal, rc));
    17122029
    17132030        if (!pRegs->picb)
     
    17482065        }
    17492066    }
    1750 
    1751     int rc2 = RTCritSectLeave(&pStream->CritSect);
    1752     AssertRC(rc2);
    17532067
    17542068    if (RT_SUCCESS(rc))
     
    19892303                case MC_CR:
    19902304                {
    1991                     if (u32Val & AC97_CR_RR) /* Busmaster reset */
     2305                    Log3Func(("[SD%RU8] CR <- %#x (cr %#x)\n", pStream->u8Strm, u32Val, pRegs->cr));
     2306
     2307                    if (u32Val & AC97_CR_RR) /* Busmaster reset. */
    19922308                    {
     2309                        Log3Func(("[SD%RU8] Reset\n", pStream->u8Strm));
     2310
     2311                        /* Make sure that Run/Pause Bus Master bit (RPBM) is cleared (0). */
     2312                        Assert((pRegs->cr & AC97_CR_RPBM) == 0);
     2313
    19932314                        ichac97StreamResetBMRegs(pThis, pStream);
    19942315                    }
     
    19962317                    {
    19972318                        pRegs->cr = u32Val & AC97_CR_VALID_MASK;
     2319
    19982320                        if (!(pRegs->cr & AC97_CR_RPBM))
    19992321                        {
    2000                             ichac97StreamEnable(pThis, pStream, false /* fActive */);
     2322                            Log3Func(("[SD%RU8] Disable\n", pStream->u8Strm));
     2323
     2324                            ichac97StreamEnable(pThis, pStream, false /* fEnable */);
    20012325
    20022326                            pRegs->sr |= AC97_SR_DCH;
     
    20042328                        else
    20052329                        {
     2330                            Log3Func(("[SD%RU8] Enable\n", pStream->u8Strm));
     2331
    20062332                            pRegs->civ = pRegs->piv;
    20072333                            pRegs->piv = (pRegs->piv + 1) % 32;
     
    20122338                            ichac97StreamFetchBDLE(pThis, pStream);
    20132339
    2014                             ichac97StreamEnable(pThis, pStream, true /* fActive */);
     2340                            ichac97StreamEnable(pThis, pStream, true /* fEnable */);
    20152341                        }
    20162342                    }
    2017                     Log3Func(("[SD%RU8] CR <- %#x (cr %#x)\n", pStream->u8Strm, u32Val, pRegs->cr));
    20182343                    break;
    20192344                }
     
    22332558                        ichac97StreamReOpen(pThis, &pThis->StreamLineIn);
    22342559                    }
     2560                    else
     2561                        LogRel2(("AC97: Variable rate audio (VRA) is not supported\n"));
     2562
    22352563                    if (!(u32Val & AC97_EACS_VRM))
    22362564                    {
     
    22382566                        ichac97StreamReOpen(pThis, &pThis->StreamMicIn);
    22392567                    }
     2568                    else
     2569                        LogRel2(("AC97: Variable rate microphone audio (VRM) is not supported\n"));
     2570
    22402571                    LogFunc(("Setting extended audio control to %#x\n", u32Val));
    22412572                    ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, u32Val);
     
    30613392         * Register statistics.
    30623393         */
    3063         PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer,            STAMTYPE_PROFILE, "/Devices/AC97/Timer",             STAMUNIT_TICKS_PER_CALL, "Profiling ichac97Timer.");
    3064         PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead,        STAMTYPE_COUNTER, "/Devices/AC97/BytesRead"   ,      STAMUNIT_BYTES,          "Bytes read from AC97 emulation.");
    3065         PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten,     STAMTYPE_COUNTER, "/Devices/AC97/BytesWritten",      STAMUNIT_BYTES,          "Bytes written to AC97 emulation.");
    3066     }
     3394        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer,        STAMTYPE_PROFILE, "/Devices/AC97/Timer",        STAMUNIT_TICKS_PER_CALL, "Profiling ichac97Timer.");
     3395        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn,           STAMTYPE_PROFILE, "/Devices/AC97/Input",        STAMUNIT_TICKS_PER_CALL, "Profiling input.");
     3396        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatOut,          STAMTYPE_PROFILE, "/Devices/AC97/Output",       STAMUNIT_TICKS_PER_CALL, "Profiling output.");
     3397        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead,    STAMTYPE_COUNTER, "/Devices/AC97/BytesRead"   , STAMUNIT_BYTES,          "Bytes read from AC97 emulation.");
     3398        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "/Devices/AC97/BytesWritten", STAMUNIT_BYTES,          "Bytes written to AC97 emulation.");
     3399    }
     3400#endif
     3401
     3402#ifdef AC97_DEBUG_DUMP_PCM_DATA
     3403    RTFileDelete(AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97DMARead.pcm");
     3404    RTFileDelete(AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97DMAWrite.pcm");
     3405    RTFileDelete(AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97StreamRead.pcm");
     3406    RTFileDelete(AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97StreamWrite.pcm");
    30673407#endif
    30683408
Note: See TracChangeset for help on using the changeset viewer.

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