VirtualBox

Changeset 76179 in vbox


Ignore:
Timestamp:
Dec 12, 2018 2:51:09 PM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
127434
Message:

Audio/AC97: Fixed audio delays by using the same way of (Hz- and time-based) calculations as the HDA emulation utilizes. While at it, also implemented separate timers for each stream (as for HDA also), helping to keep timing per stream more accurate.

File:
1 edited

Legend:

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

    r76158 r76179  
    5151
    5252/** Default timer frequency (in Hz). */
    53 #define AC97_TIMER_HZ_DEFAULT 200
     53#define AC97_TIMER_HZ_DEFAULT 100
     54
     55/** Maximum number of streams we support. */
     56#define AC97_MAX_STREAMS      3
    5457
    5558/** Maximum FIFO size (in bytes). */
     
    219222
    220223#ifndef VBOX_DEVICE_STRUCT_TESTCASE
     224/**
     225 * Enumeration of AC'97 source indices.
     226 *
     227 * Note: The order of this indices is fixed (also applies for saved states) for the moment.
     228 *       So make sure you know what you're done when altering this.
     229 */
    221230typedef enum
    222231{
     
    256265    uint32_t addr;
    257266    uint32_t ctl_len;
    258 } AC97BDLE, *PAC97BDLE;
     267} AC97BDLE;
     268AssertCompileSize(AC97BDLE, 8);
     269/** Pointer to BDLE. */
     270typedef AC97BDLE *PAC97BDLE;
    259271
    260272/**
     
    299311#endif
    300312
     313/** The ICH AC'97 (Intel) controller. */
     314typedef struct AC97STATE *PAC97STATE;
     315
    301316/**
    302317 * Structure for keeping the internal state of an AC'97 stream.
     
    318333    AC97STREAMSTATEAIO    AIO;
    319334#endif
    320     /** Timestamp (in ns) of last DMA transfer.
    321      *  For output streams this is the last DMA read,
    322      *  for input streams this is the last DMA write. */
    323     uint64_t              tsLastTransferNs;
    324     /** Timestamp (in ns) of last DMA buffer read / write. */
    325     uint64_t              tsLastReadWriteNs;
    326     /** Timestamp (in ns) of last stream update. */
     335    /** Timestamp of the last DMA data transfer. */
     336    uint64_t              tsTransferLast;
     337    /** Timestamp of the next DMA data transfer.
     338     *  Next for determining the next scheduling window.
     339     *  Can be 0 if no next transfer is scheduled. */
     340    uint64_t              tsTransferNext;
     341    /** Total transfer size (in bytes) of a transfer period. */
     342    uint32_t              cbTransferSize;
     343    /** Transfer chunk size (in bytes) of a transfer period. */
     344    uint32_t              cbTransferChunk;
     345    /** How many bytes already have been processed in within
     346     *  the current transfer period. */
     347    uint32_t              cbTransferProcessed;
     348    /** The stream's timer Hz rate.
     349     *  This value can can be different from the device's default Hz rate,
     350     *  depending on the rate the stream expects (e.g. for 5.1 speaker setups).
     351     *  Set in R3StreamInit(). */
     352    uint16_t              uTimerHz;
     353    uint8_t               Padding3[2];
     354    /** (Virtual) clock ticks per byte. */
     355    uint64_t              cTicksPerByte;
     356    /** (Virtual) clock ticks per transfer. */
     357    uint64_t              cTransferTicks;
     358   /** Timestamp (in ns) of last stream update. */
    327359    uint64_t              tsLastUpdateNs;
    328360} AC97STREAMSTATE;
     
    364396{
    365397    /** Stream number (SDn). */
    366     uint8_t           u8SD;
    367     uint8_t           abPadding[7];
     398    uint8_t               u8SD;
     399    uint8_t               abPadding[7];
    368400    /** Bus master registers of this stream. */
    369     AC97BMREGS        Regs;
     401    AC97BMREGS            Regs;
    370402    /** Internal state of this stream. */
    371     AC97STREAMSTATE   State;
     403    AC97STREAMSTATE       State;
     404    /** Pointer to parent (AC'97 state). */
     405    R3PTRTYPE(PAC97STATE) pAC97State;
    372406    /** Debug information. */
    373     AC97STREAMDBGINFO Dbg;
     407    AC97STREAMDBGINFO     Dbg;
    374408} AC97STREAM, *PAC97STREAM;
    375409AssertCompileSizeAlignment(AC97STREAM, 8);
     
    464498    uint32_t                last_samp;
    465499    uint8_t                 mixer_data[256];
    466     /** AC'97 stream for line-in. */
    467     AC97STREAM              StreamLineIn;
    468     /** AC'97 stream for microphone-in. */
    469     AC97STREAM              StreamMicIn;
    470     /** AC'97 stream for output. */
    471     AC97STREAM              StreamOut;
    472     /** Number of active (running) SDn streams. */
    473     uint8_t                 cStreamsActive;
    474     /** Flag indicating whether the timer is active or not. */
    475     bool                    fTimerActive;
     500    /** Array of AC'97 streams. */
     501    AC97STREAM              aStreams[AC97_MAX_STREAMS];
    476502    /** The device timer Hz rate. Defaults to AC97_TIMER_HZ_DEFAULT_DEFAULT. */
    477503    uint16_t                uTimerHz;
    478504    /** The timer for pumping data thru the attached LUN drivers - RCPtr. */
    479     PTMTIMERRC              pTimerRC;
     505    PTMTIMERRC              pTimerRC[AC97_MAX_STREAMS];
    480506    /** The timer for pumping data thru the attached LUN drivers - R3Ptr. */
    481     PTMTIMERR3              pTimerR3;
     507    PTMTIMERR3              pTimerR3[AC97_MAX_STREAMS];
    482508    /** The timer for pumping data thru the attached LUN drivers - R0Ptr. */
    483     PTMTIMERR0              pTimerR0;
    484     /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
    485     uint64_t                cTimerTicks;
    486     /** Timestamp of the last timer callback (ac97Timer).
    487      * Used to calculate the time actually elapsed between two timer callbacks. */
    488     uint64_t                uTimerTS;
     509    PTMTIMERR0              pTimerR0[AC97_MAX_STREAMS];
    489510#ifdef VBOX_WITH_STATISTICS
    490511    STAMPROFILE             StatTimer;
     
    517538    AC97STATEDBGINFO        Dbg;
    518539} AC97STATE;
    519 AssertCompileMemberAlignment(AC97STATE, StreamLineIn, 8);
     540AssertCompileMemberAlignment(AC97STATE, aStreams, 8);
    520541/** Pointer to a AC'97 state. */
    521542typedef AC97STATE *PAC97STATE;
     
    556577    } while (0)
    557578
     579#ifdef IN_RC
     580/** Retrieves an attribute from a specific audio stream in RC. */
     581# define DEVAC97_CTX_SUFF_SD(a_Var, a_SD)      a_Var##RC[a_SD]
     582#elif defined(IN_RING0)
     583/** Retrieves an attribute from a specific audio stream in R0. */
     584# define DEVAC97_CTX_SUFF_SD(a_Var, a_SD)      a_Var##R0[a_SD]
     585#else
     586/** Retrieves an attribute from a specific audio stream in R3. */
     587# define DEVAC97_CTX_SUFF_SD(a_Var, a_SD)      a_Var##R3[a_SD]
     588#endif
     589
    558590/**
    559591 * Releases the AC'97 lock.
     
    565597 * Acquires the TM lock and AC'97 lock, returns on failure.
    566598 */
    567 #define DEVAC97_LOCK_BOTH_RETURN_VOID(a_pThis) \
     599#define DEVAC97_LOCK_BOTH_RETURN_VOID(a_pThis, a_SD) \
    568600    do { \
    569         int rcLock = TMTimerLock((a_pThis)->CTX_SUFF(pTimer), VERR_IGNORED); \
     601        int rcLock = TMTimerLock((a_pThis)->DEVAC97_CTX_SUFF_SD(pTimer, a_SD), VERR_IGNORED); \
    570602        if (rcLock != VINF_SUCCESS) \
    571603        { \
     
    577609        { \
    578610            AssertRC(rcLock); \
    579             TMTimerUnlock((a_pThis)->CTX_SUFF(pTimer)); \
     611            TMTimerUnlock((a_pThis)->DEVAC97_CTX_SUFF_SD(pTimer, a_SD)); \
    580612            return; \
    581613        } \
     
    585617 * Acquires the TM lock and AC'97 lock, returns on failure.
    586618 */
    587 #define DEVAC97_LOCK_BOTH_RETURN(a_pThis, a_rcBusy) \
     619#define DEVAC97_LOCK_BOTH_RETURN(a_pThis, a_SD, a_rcBusy) \
    588620    do { \
    589         int rcLock = TMTimerLock((a_pThis)->CTX_SUFF(pTimer), (a_rcBusy)); \
     621        int rcLock = TMTimerLock((a_pThis)->DEVAC97_CTX_SUFF_SD(pTimer, a_SD), (a_rcBusy)); \
    590622        if (rcLock != VINF_SUCCESS) \
    591623            return rcLock; \
     
    594626        { \
    595627            AssertRC(rcLock); \
    596             TMTimerUnlock((a_pThis)->CTX_SUFF(pTimer)); \
     628            TMTimerUnlock((a_pThis)->DEVAC97_CTX_SUFF_SD(pTimer, a_SD)); \
    597629            return rcLock; \
    598630        } \
     
    602634 * Releases the AC'97 lock and TM lock.
    603635 */
    604 #define DEVAC97_UNLOCK_BOTH(a_pThis) \
     636#define DEVAC97_UNLOCK_BOTH(a_pThis, a_SD) \
    605637    do { \
    606638        PDMCritSectLeave(&(a_pThis)->CritSect); \
    607         TMTimerUnlock((a_pThis)->CTX_SUFF(pTimer)); \
     639        TMTimerUnlock((a_pThis)->DEVAC97_CTX_SUFF_SD(pTimer, a_SD)); \
    608640    } while (0)
    609641
     
    636668static DECLCALLBACK(void) ichac97R3Reset(PPDMDEVINS pDevIns);
    637669
    638 static int                ichac97R3TimerStart(PAC97STATE pThis);
    639 static int                ichac97R3TimerMaybeStart(PAC97STATE pThis);
    640 static int                ichac97R3TimerStop(PAC97STATE pThis);
    641 static int                ichac97R3TimerMaybeStop(PAC97STATE pThis);
    642 static void               ichac97R3TimerMain(PAC97STATE pThis);
    643670static DECLCALLBACK(void) ichac97R3Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
    644 
    645 static void               ichac97R3DoTransfers(PAC97STATE pThis);
    646671
    647672static int                ichac97R3MixerAddDrv(PAC97STATE pThis, PAC97DRIVER pDrv);
     
    663688
    664689DECLINLINE(PDMAUDIODIR)   ichac97GetDirFromSD(uint8_t uSD);
     690
     691# ifdef LOG_ENABLED
     692static void               ichac97R3BDLEDumpAll(PAC97STATE pThis, uint64_t u64BDLBase, uint16_t cBDLE);
     693# endif
    665694#endif /* IN_RING3 */
    666695
     
    714743    PAC97BMREGS pRegs   = &pStream->Regs;
    715744
    716     uint32_t u32[2];
    717 
    718     PDMDevHlpPhysRead(pDevIns, pRegs->bdbar + pRegs->civ * 8, &u32[0], sizeof(u32));
     745    AC97BDLE BDLE;
     746    PDMDevHlpPhysRead(pDevIns, pRegs->bdbar + pRegs->civ * sizeof(AC97BDLE), &BDLE, sizeof(AC97BDLE));
    719747    pRegs->bd_valid   = 1;
    720748# ifndef RT_LITTLE_ENDIAN
    721749#  error "Please adapt the code (audio buffers are little endian)!"
    722750# else
    723     pRegs->bd.addr    = RT_H2LE_U32(u32[0] & ~3);
    724     pRegs->bd.ctl_len = RT_H2LE_U32(u32[1]);
     751    pRegs->bd.addr    = RT_H2LE_U32(BDLE.addr & ~3);
     752    pRegs->bd.ctl_len = RT_H2LE_U32(BDLE.ctl_len);
    725753# endif
    726754    pRegs->picb       = pRegs->bd.ctl_len & AC97_BD_LEN_MASK;
     
    779807    {
    780808        static uint32_t const s_aMasks[] = { AC97_GS_PIINT, AC97_GS_POINT, AC97_GS_MINT };
     809        Assert(pStream->u8SD < AC97_MAX_STREAMS);
    781810        if (iIRQL)
    782811            pThis->glob_sta |=  s_aMasks[pStream->u8SD];
     
    876905    ichac97R3StreamUnlock(pStream);
    877906
    878     /* Second, see if we need to start or stop the timer. */
    879     if (!fEnable)
    880         ichac97R3TimerMaybeStop(pThis);
    881     else
    882         ichac97R3TimerMaybeStart(pThis);
    883 
    884     LogFunc(("[SD%RU8] cStreamsActive=%RU8, fEnable=%RTbool, rc=%Rrc\n", pStream->u8SD, pThis->cStreamsActive, fEnable, rc));
     907    LogFunc(("[SD%RU8] fEnable=%RTbool, rc=%Rrc\n", pStream->u8SD, fEnable, rc));
    885908    return rc;
    886909}
     
    927950 * @param   pThis               AC'97 state.
    928951 * @param   pStream             AC'97 stream to create.
    929  * @param   u8Strm              Stream ID to assign AC'97 stream to.
    930  */
    931 static int ichac97R3StreamCreate(PAC97STATE pThis, PAC97STREAM pStream, uint8_t u8Strm)
     952 * @param   u8SD                Stream descriptor number to assign.
     953 */
     954static int ichac97R3StreamCreate(PAC97STATE pThis, PAC97STREAM pStream, uint8_t u8SD)
    932955{
    933956    RT_NOREF(pThis);
     
    935958    /** @todo Validate u8Strm. */
    936959
    937     LogFunc(("[SD%RU8] pStream=%p\n", u8Strm, pStream));
    938 
    939     Assert(u8Strm < 3);
    940     pStream->u8SD = u8Strm;
     960    LogFunc(("[SD%RU8] pStream=%p\n", u8SD, pStream));
     961
     962    AssertReturn(u8SD < AC97_MAX_STREAMS, VERR_INVALID_PARAMETER);
     963    pStream->u8SD       = u8SD;
     964    pStream->pAC97State = pThis;
    941965
    942966    int rc = RTCritSectInit(&pStream->State.CritSect);
     
    10331057     * Destroy all AC'97 streams.
    10341058     */
    1035 
    1036     ichac97R3StreamDestroy(pThis, &pThis->StreamLineIn);
    1037     ichac97R3StreamDestroy(pThis, &pThis->StreamMicIn);
    1038     ichac97R3StreamDestroy(pThis, &pThis->StreamOut);
     1059    for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
     1060        ichac97R3StreamDestroy(pThis, &pThis->aStreams[i]);
    10391061
    10401062    /*
     
    11111133    RTCircBufReleaseWriteBlock(pCircBuf, cbRead);
    11121134
    1113     pDstStream->State.tsLastReadWriteNs = RTTimeNanoTS();
    1114 
    11151135    if (pcbWritten)
    11161136        *pcbWritten = cbRead;
     
    11811201    }
    11821202
    1183     pSrcStream->State.tsLastReadWriteNs = RTTimeNanoTS();
    1184 
    11851203    if (pcbRead)
    11861204        *pcbRead = cbReadTotal;
     
    13991417}
    14001418#endif
    1401 
    14021419# endif /* VBOX_WITH_AUDIO_AC97_ASYNC_IO */
     1420
     1421# ifdef LOG_ENABLED
     1422static void ichac97R3BDLEDumpAll(PAC97STATE pThis, uint64_t u64BDLBase, uint16_t cBDLE)
     1423{
     1424    LogFlowFunc(("BDLEs @ 0x%x (%RU16):\n", u64BDLBase, cBDLE));
     1425    if (!u64BDLBase)
     1426        return;
     1427
     1428    uint32_t cbBDLE = 0;
     1429    for (uint16_t i = 0; i < cBDLE; i++)
     1430    {
     1431        AC97BDLE BDLE;
     1432        PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), u64BDLBase + i * sizeof(AC97BDLE), &BDLE, sizeof(AC97BDLE));
     1433
     1434        BDLE.addr    = RT_H2LE_U32(BDLE.addr & ~3);
     1435        BDLE.ctl_len = RT_H2LE_U32(BDLE.ctl_len);
     1436
     1437        LogFunc(("\t#%03d BDLE(adr:0x%llx, size:%RU32 [%RU32 bytes])\n",
     1438                  i, BDLE.addr,
     1439                  BDLE.ctl_len & AC97_BD_LEN_MASK,
     1440                 (BDLE.ctl_len & AC97_BD_LEN_MASK) << 1)); /** @todo r=andy Assumes 16bit samples. */
     1441
     1442        cbBDLE += (BDLE.ctl_len & AC97_BD_LEN_MASK) << 1; /** @todo r=andy Ditto. */
     1443    }
     1444
     1445    LogFlowFunc(("Total: %RU32 bytes\n", cbBDLE));
     1446}
     1447# endif /* LOG_ENABLED */
    14031448
    14041449/**
     
    14441489# endif
    14451490        {
     1491            uint32_t cbTransferChunk = (pStream->State.Cfg.Props.uHz / pStream->State.uTimerHz)
     1492                                     * DrvAudioHlpPCMPropsBytesPerFrame(&pStream->State.Cfg.Props);
     1493
    14461494            const uint32_t cbStreamFree = ichac97R3StreamGetFree(pStream);
    14471495            if (cbStreamFree)
    14481496            {
    14491497                /* Do the DMA transfer. */
    1450                 rc2 = ichac97R3StreamTransfer(pThis, pStream, cbStreamFree);
     1498                rc2 = ichac97R3StreamTransfer(pThis, pStream, RT_MIN(cbStreamFree, cbTransferChunk));
    14511499                AssertRC(rc2);
    14521500            }
     
    17751823    int rc = VINF_SUCCESS;
    17761824
    1777     if (DrvAudioHlpStreamCfgIsValid(&pThis->StreamLineIn.State.Cfg))
    1778     {
    1779         int rc2 = ichac97R3MixerAddDrvStream(pThis, pThis->pSinkLineIn, &pThis->StreamLineIn.State.Cfg, pDrv);
     1825    if (DrvAudioHlpStreamCfgIsValid(&pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX].State.Cfg))
     1826    {
     1827        int rc2 = ichac97R3MixerAddDrvStream(pThis, pThis->pSinkLineIn,
     1828                                             &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX].State.Cfg, pDrv);
    17801829        if (RT_SUCCESS(rc))
    17811830            rc = rc2;
    17821831    }
    17831832
    1784     if (DrvAudioHlpStreamCfgIsValid(&pThis->StreamMicIn.State.Cfg))
    1785     {
    1786         int rc2 = ichac97R3MixerAddDrvStream(pThis, pThis->pSinkMicIn,  &pThis->StreamMicIn.State.Cfg, pDrv);
     1833    if (DrvAudioHlpStreamCfgIsValid(&pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX].State.Cfg))
     1834    {
     1835        int rc2 = ichac97R3MixerAddDrvStream(pThis, pThis->pSinkOut,
     1836                                             &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX].State.Cfg, pDrv);
    17871837        if (RT_SUCCESS(rc))
    17881838            rc = rc2;
    17891839    }
    17901840
    1791     if (DrvAudioHlpStreamCfgIsValid(&pThis->StreamOut.State.Cfg))
    1792     {
    1793         int rc2 = ichac97R3MixerAddDrvStream(pThis, pThis->pSinkOut,    &pThis->StreamOut.State.Cfg, pDrv);
     1841    if (DrvAudioHlpStreamCfgIsValid(&pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX].State.Cfg))
     1842    {
     1843        int rc2 = ichac97R3MixerAddDrvStream(pThis, pThis->pSinkMicIn,
     1844                                             &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX].State.Cfg, pDrv);
    17941845        if (RT_SUCCESS(rc))
    17951846            rc = rc2;
     
    19792030                }
    19802031
    1981                 rc = RTCircBufCreate(&pStream->State.pCircBuf, DrvAudioHlpMilliToBytes(500 /* ms */, &Cfg.Props)); /** @todo Make this configurable. */
     2032                rc = RTCircBufCreate(&pStream->State.pCircBuf, DrvAudioHlpMilliToBytes(100 /* ms */, &Cfg.Props)); /** @todo Make this configurable. */
    19822033                if (RT_SUCCESS(rc))
    19832034                {
     
    19882039                        rc = DrvAudioHlpStreamCfgCopy(&pStream->State.Cfg, &Cfg);
    19892040                }
     2041
     2042                /*
     2043                 * Set the stream's timer Hz rate.
     2044                 *
     2045                 * Currently we simply apply the global Hz rate.
     2046                 * This might needs tweaking as we add surround support and/or channel striping later. */
     2047                pStream->State.uTimerHz = pThis->uTimerHz;
     2048
     2049                /*
     2050                 * Set up data transfer stuff.
     2051                 */
     2052#ifdef LOG_ENABLED
     2053                ichac97R3BDLEDumpAll(pThis, pStream->Regs.bdbar, pStream->Regs.lvi + 1);
     2054#endif
     2055                const uint32_t cbFrame = DrvAudioHlpPCMPropsBytesPerFrame(&Cfg.Props);
     2056
     2057                /* Calculate the fragment size the guest OS expects interrupt delivery at. */
     2058                pStream->State.cbTransferSize = 441 * 4;//pStream->u32CBL / cFragments;
     2059                Assert(pStream->State.cbTransferSize);
     2060                Assert(pStream->State.cbTransferSize % cbFrame == 0);
     2061
     2062                /* Calculate the bytes we need to transfer to / from the stream's DMA per iteration.
     2063                 * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. */
     2064                pStream->State.cbTransferChunk = (pStream->State.Cfg.Props.uHz / pStream->State.uTimerHz) * cbFrame;
     2065                Assert(pStream->State.cbTransferChunk);
     2066                Assert(pStream->State.cbTransferChunk % cbFrame== 0);
     2067
     2068                /* Make sure that the transfer chunk does not exceed the overall transfer size. */
     2069                if (pStream->State.cbTransferChunk > pStream->State.cbTransferSize)
     2070                    pStream->State.cbTransferChunk = pStream->State.cbTransferSize;
     2071
     2072                const uint64_t cTicksPerHz = TMTimerGetFreq((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD))/ pStream->State.uTimerHz;
     2073
     2074                /* Calculate the timer ticks per byte for this stream. */
     2075                pStream->State.cTicksPerByte = cTicksPerHz / pStream->State.cbTransferChunk;
     2076                Assert(pStream->State.cTicksPerByte);
     2077
     2078                /* Calculate timer ticks per transfer. */
     2079                pStream->State.cTransferTicks     = pStream->State.cbTransferChunk * pStream->State.cTicksPerByte;
     2080                Assert(pStream->State.cTransferTicks);
     2081
     2082                LogFunc(("[SD%RU8] Timer %uHz (%RU64 ticks per Hz), cTicksPerByte=%RU64, cbTransferChunk=%RU32, cTransferTicks=%RU64, " \
     2083                         "cbTransferSize=%RU32\n",
     2084                         pStream->u8SD, pStream->State.uTimerHz, cTicksPerHz, pStream->State.cTicksPerByte,
     2085                         pStream->State.cbTransferChunk, pStream->State.cTransferTicks, pStream->State.cbTransferSize));
     2086
    19902087            }
    19912088        }
     
    23422439    }
    23432440
     2441    AssertFailed();
    23442442    return PDMAUDIODIR_UNKNOWN;
    23452443}
    23462444
    23472445#endif /* IN_RING3 */
    2348 
    2349 /**
    2350  * Retrieves an AC'97 audio stream from an AC'97 stream index.
    2351  *
    2352  * @returns Pointer to AC'97 audio stream if found, or NULL if not found / invalid.
    2353  * @param   pThis               AC'97 state.
    2354  * @param   uIdx                AC'97 stream index to retrieve AC'97 audio stream for.
    2355  */
    2356 DECLINLINE(PAC97STREAM) ichac97GetStreamFromIdx(PAC97STATE pThis, uint32_t uIdx)
    2357 {
    2358     switch (uIdx)
    2359     {
    2360         case AC97SOUNDSOURCE_PI_INDEX: return &pThis->StreamLineIn;
    2361         case AC97SOUNDSOURCE_MC_INDEX: return &pThis->StreamMicIn;
    2362         case AC97SOUNDSOURCE_PO_INDEX: return &pThis->StreamOut;
    2363         default:                       return NULL;
    2364     }
    2365 
    2366 }
    23672446
    23682447#ifdef IN_RING3
     
    25022581
    25032582/**
    2504  * Starts the internal audio device timer.
    2505  *
    2506  * @return  IPRT status code.
    2507  * @param   pThis               AC'97 state.
    2508  */
    2509 static int  ichac97R3TimerStart(PAC97STATE pThis)
    2510 {
    2511     LogFlowFuncEnter();
    2512 
    2513     DEVAC97_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
    2514 
    2515     AssertPtr(pThis->CTX_SUFF(pTimer));
    2516 
    2517     if (!pThis->fTimerActive)
    2518     {
    2519         LogRel2(("AC97: Starting transfers\n"));
    2520 
    2521         pThis->fTimerActive = true;
    2522 
    2523         /* Start transfers. */
    2524         ichac97R3TimerMain(pThis);
    2525     }
    2526 
    2527     DEVAC97_UNLOCK_BOTH(pThis);
    2528 
    2529     return VINF_SUCCESS;
    2530 }
    2531 
    2532 /**
    2533  * Starts the internal audio device timer (if not started yet).
    2534  *
    2535  * @return  IPRT status code.
    2536  * @param   pThis               AC'97 state.
    2537  */
    2538 static int ichac97R3TimerMaybeStart(PAC97STATE pThis)
    2539 {
    2540     LogFlowFuncEnter();
    2541 
    2542     if (!pThis->CTX_SUFF(pTimer))
    2543         return VERR_WRONG_ORDER;
    2544 
    2545     pThis->cStreamsActive++;
    2546 
    2547     /* Only start the timer at the first active stream. */
    2548     if (pThis->cStreamsActive == 1)
    2549         return ichac97R3TimerStart(pThis);
    2550 
    2551     return VINF_SUCCESS;
    2552 }
    2553 
    2554 /**
    2555  * Stops the internal audio device timer.
    2556  *
    2557  * @return  IPRT status code.
    2558  * @param   pThis               AC'97 state.
    2559  */
    2560 static int ichac97R3TimerStop(PAC97STATE pThis)
    2561 {
    2562     LogFlowFuncEnter();
    2563 
    2564     if (!pThis->CTX_SUFF(pTimer)) /* Only can happen on device construction time, so no locking needed here. */
    2565         return VINF_SUCCESS;
    2566 
    2567     DEVAC97_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
    2568 
    2569     if (pThis->fTimerActive)
    2570     {
    2571         LogRel2(("AC97: Stopping transfers ...\n"));
    2572 
    2573         pThis->fTimerActive = false;
    2574 
    2575         /* Note: Do not stop the timer via TMTimerStop() here, as there still might
    2576          *       be queued audio data which needs to be handled (e.g. played back) first
    2577          *       before actually stopping the timer for good. */
    2578     }
    2579 
    2580     DEVAC97_UNLOCK_BOTH(pThis);
    2581 
    2582     return VINF_SUCCESS;
    2583 }
    2584 
    2585 /**
    2586  * Decreases the active AC'97 streams count by one and
    2587  * then checks if the internal audio device timer can be
    2588  * stopped.
    2589  *
    2590  * @return  IPRT status code.
    2591  * @param   pThis               AC'97 state.
    2592  */
    2593 static int ichac97R3TimerMaybeStop(PAC97STATE pThis)
    2594 {
    2595     LogFlowFuncEnter();
    2596 
    2597     if (!pThis->CTX_SUFF(pTimer))
    2598         return VERR_WRONG_ORDER;
    2599 
    2600     if (pThis->cStreamsActive) /* Function can be called mupltiple times. */
    2601     {
    2602         pThis->cStreamsActive--;
    2603 
    2604         if (pThis->cStreamsActive == 0)
    2605             return ichac97R3TimerStop(pThis);
    2606     }
    2607 
    2608     return VINF_SUCCESS;
    2609 }
    2610 
    2611 /**
    2612  * Main routine for the device timer.
    2613  *
    2614  * @param   pThis               AC'97 state.
    2615  */
    2616 static void ichac97R3TimerMain(PAC97STATE pThis)
    2617 {
    2618     STAM_PROFILE_START(&pThis->StatTimer, a);
    2619 
    2620     DEVAC97_LOCK_BOTH_RETURN_VOID(pThis);
    2621 
    2622     uint64_t cTicksNow = TMTimerGet(pThis->CTX_SUFF(pTimer));
    2623 
    2624     /* Update current time timestamp. */
    2625     pThis->uTimerTS = cTicksNow;
    2626 
    2627     /* Flag indicating whether to arm the timer again for the next DMA transfer or sink processing. */
    2628     bool fArmTimer = false;
    2629 
    2630     ichac97R3DoTransfers(pThis);
    2631 
    2632     /* Do we need to arm the timer again? */
    2633     if (   AudioMixerSinkIsActive(ichac97R3IndexToSink(pThis, pThis->StreamLineIn.u8SD))
    2634         || AudioMixerSinkIsActive(ichac97R3IndexToSink(pThis, pThis->StreamMicIn.u8SD))
    2635         || AudioMixerSinkIsActive(ichac97R3IndexToSink(pThis, pThis->StreamOut.u8SD)))
    2636     {
    2637         fArmTimer = true;
    2638     }
    2639 
    2640     if (   ASMAtomicReadBool(&pThis->fTimerActive) /** @todo r=bird: totally unnecessary to do atomic read here, isn't it? */
    2641         || fArmTimer)
    2642     {
    2643         /* Arm the timer again. */
    2644         uint64_t cTicks = pThis->cTimerTicks;
    2645         /** @todo adjust cTicks down by now much cbOutMin represents. */
    2646         TMTimerSet(pThis->CTX_SUFF(pTimer), cTicksNow + cTicks);
    2647     }
    2648     else
    2649         LogRel2(("AC97: Stopped transfers\n"));
    2650 
    2651     DEVAC97_UNLOCK_BOTH(pThis);
    2652 
    2653     STAM_PROFILE_STOP(&pThis->StatTimer, a);
    2654 }
    2655 
    2656 /**
    26572583 * Timer callback which handles the audio data transfers on a periodic basis.
    26582584 *
     
    26652591    RT_NOREF(pDevIns, pTimer);
    26662592
    2667     PAC97STATE pThis = (PAC97STATE)pvUser;
    2668     Assert(pThis == PDMINS_2_DATA(pDevIns, PAC97STATE));
    2669 
    2670     ichac97R3TimerMain(pThis);
    2671 }
    2672 
    2673 /**
    2674  * Main routine to perform the actual audio data transfers from the AC'97 streams
    2675  * to the backend(s) and vice versa.
    2676  *
     2593    PAC97STREAM pStream = (PAC97STREAM)pvUser;
     2594    AssertPtr(pStream);
     2595
     2596    PAC97STATE  pThis   = pStream->pAC97State;
     2597    AssertPtr(pThis);
     2598
     2599    STAM_PROFILE_START(&pThis->StatTimer, a);
     2600
     2601    DEVAC97_LOCK_BOTH_RETURN_VOID(pThis, pStream->u8SD);
     2602
     2603    ichac97R3StreamUpdate(pThis, pStream, true /* fInTimer */);
     2604
     2605    PAUDMIXSINK pSink = ichac97R3IndexToSink(pThis, pStream->u8SD);
     2606
     2607    bool fSinkActive = false;
     2608    if (pSink)
     2609        fSinkActive = AudioMixerSinkIsActive(pSink);
     2610
     2611    if (fSinkActive)
     2612    {
     2613        TMTimerSet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD),
     2614                   TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks);
     2615    }
     2616
     2617    DEVAC97_UNLOCK_BOTH(pThis, pStream->u8SD);
     2618
     2619    STAM_PROFILE_STOP(&pThis->StatTimer, a);
     2620}
     2621
     2622/**
     2623 * Sets the virtual device timer to a new expiration time.
     2624 *
     2625 * @returns Whether the new expiration time was set or not.
    26772626 * @param   pThis               AC'97 state.
    2678  */
    2679 static void ichac97R3DoTransfers(PAC97STATE pThis)
    2680 {
    2681     AssertPtrReturnVoid(pThis);
    2682 
    2683     ichac97R3StreamUpdate(pThis, &pThis->StreamLineIn, true /* fInTimer */);
    2684     ichac97R3StreamUpdate(pThis, &pThis->StreamMicIn,  true /* fInTimer */);
    2685     ichac97R3StreamUpdate(pThis, &pThis->StreamOut,    true /* fInTimer */);
     2627 * @param   pStream             AC'97 stream to set timer for.
     2628 * @param   tsExpire            New (virtual) expiration time to set.
     2629 * @param   fForce              Whether to force setting the expiration time or not.
     2630 *
     2631 * @remark  This function takes all active AC'97 streams and their
     2632 *          current timing into account. This is needed to make sure
     2633 *          that all streams can match their needed timing.
     2634 *
     2635 *          To achieve this, the earliest (lowest) timestamp of all
     2636 *          active streams found will be used for the next scheduling slot.
     2637 *
     2638 *          Forcing a new expiration time will override the above mechanism.
     2639 */
     2640bool ichac97R3TimerSet(PAC97STATE pThis, PAC97STREAM pStream, uint64_t tsExpire, bool fForce)
     2641{
     2642    AssertPtrReturn(pThis, false);
     2643    AssertPtrReturn(pStream, false);
     2644
     2645    RT_NOREF(fForce);
     2646
     2647    uint64_t tsExpireMin = tsExpire;
     2648
     2649    AssertPtr((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD));
     2650
     2651    const uint64_t tsNow = TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD));
     2652
     2653    /* Make sure to not go backwards in time, as this will assert in TMTimerSet(). */
     2654    if (tsExpireMin < tsNow)
     2655        tsExpireMin = tsNow;
     2656
     2657    int rc = TMTimerSet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD), tsExpireMin);
     2658    AssertRC(rc);
     2659
     2660    return RT_SUCCESS(rc);
    26862661}
    26872662
     
    28912866    }
    28922867
    2893     pStream->State.tsLastTransferNs = RTTimeNanoTS();
    2894 
    28952868    ichac97R3StreamUnlock(pStream);
    28962869
     
    29252898    const uint32_t uPortIdx = uPort - pThis->IOPortBase[1];
    29262899
    2927     PAC97STREAM pStream = ichac97GetStreamFromIdx(pThis, AC97_PORT2IDX(uPortIdx));
     2900    PAC97STREAM pStream = NULL;
    29282901    PAC97BMREGS pRegs   = NULL;
    29292902
    2930     if (pStream) /* Can be NULL, depending on the index (port). */
    2931         pRegs = &pStream->Regs;
     2903    if (AC97_PORT2IDX(uPortIdx) < AC97_MAX_STREAMS)
     2904    {
     2905        pStream = &pThis->aStreams[AC97_PORT2IDX(uPortIdx)];
     2906        AssertPtr(pStream);
     2907        pRegs   = &pStream->Regs;
     2908    }
    29322909
    29332910    int rc = VINF_SUCCESS;
     
    30913068    RT_NOREF(pvUser);
    30923069
    3093     DEVAC97_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_IOPORT_WRITE);
    3094 
    30953070    /* Get the index of the NABMBAR register. */
    30963071    const uint32_t uPortIdx = uPort - pThis->IOPortBase[1];
    30973072
    3098     PAC97STREAM pStream = ichac97GetStreamFromIdx(pThis, AC97_PORT2IDX(uPortIdx));
     3073    PAC97STREAM pStream = NULL;
    30993074    PAC97BMREGS pRegs   = NULL;
    31003075
    3101     if (pStream) /* Can be NULL, depending on the index (port). */
     3076    if (AC97_PORT2IDX(uPortIdx) < AC97_MAX_STREAMS)
     3077    {
     3078        pStream = &pThis->aStreams[AC97_PORT2IDX(uPortIdx)];
     3079        AssertPtr(pStream);
    31023080        pRegs = &pStream->Regs;
     3081
     3082        DEVAC97_LOCK_BOTH_RETURN(pThis, pStream->u8SD, VINF_IOM_R3_IOPORT_WRITE);
     3083    }
    31033084
    31043085    int rc = VINF_SUCCESS;
     
    31163097                case MC_LVI:
    31173098                {
     3099                    AssertPtr(pStream);
     3100                    AssertPtr(pRegs);
    31183101                    if (   (pRegs->cr & AC97_CR_RPBM)
    31193102                        && (pRegs->sr & AC97_SR_DCH))
     
    31413124                case MC_CR:
    31423125                {
     3126                    AssertPtr(pStream);
     3127                    AssertPtr(pRegs);
    31433128#ifdef IN_RING3
    31443129                    Log3Func(("[SD%RU8] CR <- %#x (cr %#x)\n", pStream->u8SD, u32Val, pRegs->cr));
     
    31783163                            /* Fetch the initial BDLE descriptor. */
    31793164                            ichac97R3StreamFetchBDLE(pThis, pStream);
    3180 
    31813165                            ichac97R3StreamEnable(pThis, pStream, true /* fEnable */);
     3166
     3167                            /* Arm the timer for this stream. */
     3168                            int rc2 = ichac97R3TimerSet(pThis, pStream,
     3169                                                        TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks,
     3170                                                        false /* fForce */);
     3171                            AssertRC(rc2);
    31823172                        }
    31833173                    }
     
    31953185                case MC_SR:
    31963186                {
     3187                    AssertPtr(pStream);
     3188                    AssertPtr(pRegs);
    31973189                    pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK);
    31983190                    ichac97StreamUpdateSR(pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK));
     
    32153207                case PO_SR:
    32163208                case MC_SR:
     3209                    AssertPtr(pStream);
     3210                    AssertPtr(pRegs);
    32173211                    /* Status Register */
    32183212                    pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK);
     
    32343228                case PO_BDBAR:
    32353229                case MC_BDBAR:
     3230                    AssertPtr(pStream);
     3231                    AssertPtr(pRegs);
    32363232                    /* Buffer Descriptor list Base Address Register */
    32373233                    pRegs->bdbar = u32Val & ~3;
     
    32663262    }
    32673263
    3268     DEVAC97_UNLOCK_BOTH(pThis);
     3264    if (pStream)
     3265        DEVAC97_UNLOCK_BOTH(pThis, pStream->u8SD);
    32693266
    32703267    return rc;
     
    33503347    RT_NOREF(pvUser);
    33513348
    3352     DEVAC97_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_IOPORT_WRITE);
     3349    DEVAC97_LOCK_RETURN(pThis, VINF_IOM_R3_IOPORT_WRITE);
    33533350
    33543351    uint32_t uPortIdx = uPort - pThis->IOPortBase[0];
     3352
    33553353    int rc = VINF_SUCCESS;
    33563354    switch (cbVal)
     
    34563454                    {
    34573455                        ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate, 48000);
    3458                         ichac97R3StreamReOpen(pThis, &pThis->StreamOut);
     3456                        ichac97R3StreamReOpen(pThis, &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX]);
    34593457
    34603458                        ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate,    48000);
    3461                         ichac97R3StreamReOpen(pThis, &pThis->StreamLineIn);
     3459                        ichac97R3StreamReOpen(pThis, &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX]);
    34623460                    }
    34633461                    else
     
    34673465                    {
    34683466                        ichac97MixerSet(pThis, AC97_MIC_ADC_Rate,       48000);
    3469                         ichac97R3StreamReOpen(pThis, &pThis->StreamMicIn);
     3467                        ichac97R3StreamReOpen(pThis, &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX]);
    34703468                    }
    34713469                    else
     
    34843482                        ichac97MixerSet(pThis, uPortIdx, u32Val);
    34853483                        LogFunc(("Set front DAC rate to %RU32\n", u32Val));
    3486                         ichac97R3StreamReOpen(pThis, &pThis->StreamOut);
     3484                        ichac97R3StreamReOpen(pThis, &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX]);
    34873485#else
    34883486                        rc = VINF_IOM_R3_IOPORT_WRITE;
     
    34983496                        ichac97MixerSet(pThis, uPortIdx, u32Val);
    34993497                        LogFunc(("Set MIC ADC rate to %RU32\n", u32Val));
    3500                         ichac97R3StreamReOpen(pThis, &pThis->StreamMicIn);
     3498                        ichac97R3StreamReOpen(pThis, &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX]);
    35013499#else
    35023500                        rc = VINF_IOM_R3_IOPORT_WRITE;
     
    35123510                        ichac97MixerSet(pThis, uPortIdx, u32Val);
    35133511                        LogFunc(("Set front LR ADC rate to %RU32\n", u32Val));
    3514                         ichac97R3StreamReOpen(pThis, &pThis->StreamLineIn);
     3512                        ichac97R3StreamReOpen(pThis, &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX]);
    35153513#else
    35163514                        rc = VINF_IOM_R3_IOPORT_WRITE;
     
    35403538    }
    35413539
    3542     DEVAC97_UNLOCK_BOTH(pThis);
     3540    DEVAC97_UNLOCK(pThis);
    35433541
    35443542    return rc;
     
    36433641
    36443642    /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
    3645     /* Note: The order the streams are saved here is critical, so don't touch. */
    3646     int rc2 = ichac97R3SaveStream(pDevIns, pSSM, &pThis->StreamLineIn);
    3647     AssertRC(rc2);
    3648     rc2 = ichac97R3SaveStream(pDevIns, pSSM, &pThis->StreamOut);
    3649     AssertRC(rc2);
    3650     rc2 = ichac97R3SaveStream(pDevIns, pSSM, &pThis->StreamMicIn);
    3651     AssertRC(rc2);
     3643    /* Note: The order the streams are loaded here is critical, so don't touch. */
     3644    for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
     3645    {
     3646        int rc2 = ichac97R3SaveStream(pDevIns, pSSM, &pThis->aStreams[i]);
     3647        AssertRC(rc2);
     3648    }
    36523649
    36533650    SSMR3PutMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
     
    36553652    uint8_t active[AC97SOUNDSOURCE_END_INDEX];
    36563653
    3657     active[AC97SOUNDSOURCE_PI_INDEX] = ichac97R3StreamIsEnabled(pThis, &pThis->StreamLineIn) ? 1 : 0;
    3658     active[AC97SOUNDSOURCE_PO_INDEX] = ichac97R3StreamIsEnabled(pThis, &pThis->StreamOut)    ? 1 : 0;
    3659     active[AC97SOUNDSOURCE_MC_INDEX] = ichac97R3StreamIsEnabled(pThis, &pThis->StreamMicIn) ? 1 : 0;
     3654    active[AC97SOUNDSOURCE_PI_INDEX] = ichac97R3StreamIsEnabled(pThis, &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX]) ? 1 : 0;
     3655    active[AC97SOUNDSOURCE_PO_INDEX] = ichac97R3StreamIsEnabled(pThis, &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX]) ? 1 : 0;
     3656    active[AC97SOUNDSOURCE_MC_INDEX] = ichac97R3StreamIsEnabled(pThis, &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX]) ? 1 : 0;
    36603657
    36613658    SSMR3PutMem(pSSM, active, sizeof(active));
     
    37063703    /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
    37073704    /* Note: The order the streams are loaded here is critical, so don't touch. */
    3708     int rc2 = ichac97R3LoadStream(pSSM, &pThis->StreamLineIn);
    3709     AssertRCReturn(rc2, rc2);
    3710     rc2 = ichac97R3LoadStream(pSSM, &pThis->StreamOut);
    3711     AssertRCReturn(rc2, rc2);
    3712     rc2 = ichac97R3LoadStream(pSSM, &pThis->StreamMicIn);
    3713     AssertRCReturn(rc2, rc2);
     3705    for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
     3706    {
     3707        int rc2 = ichac97R3LoadStream(pSSM, &pThis->aStreams[i]);
     3708        AssertRCReturn(rc2, rc2);
     3709    }
    37143710
    37153711    SSMR3GetMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
     
    37173713    /** @todo r=andy Stream IDs are hardcoded to certain streams. */
    37183714    uint8_t uaStrmsActive[AC97SOUNDSOURCE_END_INDEX];
    3719     rc2 = SSMR3GetMem(pSSM, uaStrmsActive, sizeof(uaStrmsActive));
     3715    int rc2 = SSMR3GetMem(pSSM, uaStrmsActive, sizeof(uaStrmsActive));
    37203716    AssertRCReturn(rc2, rc2);
    37213717
     
    37333729
    37343730    /** @todo r=andy Stream IDs are hardcoded to certain streams. */
    3735     rc2 = ichac97R3StreamEnable(pThis, &pThis->StreamLineIn,    RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_PI_INDEX]));
    3736     if (RT_SUCCESS(rc2))
    3737         rc2 = ichac97R3StreamEnable(pThis, &pThis->StreamMicIn, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_MC_INDEX]));
    3738     if (RT_SUCCESS(rc2))
    3739         rc2 = ichac97R3StreamEnable(pThis, &pThis->StreamOut,   RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_PO_INDEX]));
     3731    for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
     3732    {
     3733        rc2 = ichac97R3StreamEnable(pThis, &pThis->aStreams[i], RT_BOOL(uaStrmsActive[i]));
     3734        AssertRC(rc2);
     3735        /* Keep going. */
     3736    }
    37403737
    37413738    pThis->bup_flag  = 0;
     
    38093806     * Reset all streams.
    38103807     */
    3811     ichac97R3StreamEnable(pThis, &pThis->StreamLineIn, false /* fEnable */);
    3812     ichac97R3StreamReset(pThis, &pThis->StreamLineIn);
    3813 
    3814     ichac97R3StreamEnable(pThis, &pThis->StreamMicIn, false /* fEnable */);
    3815     ichac97R3StreamReset(pThis, &pThis->StreamMicIn);
    3816 
    3817     ichac97R3StreamEnable(pThis, &pThis->StreamOut, false /* fEnable */);
    3818     ichac97R3StreamReset(pThis, &pThis->StreamOut);
     3808    for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
     3809    {
     3810        ichac97R3StreamEnable(pThis, &pThis->aStreams[i], false /* fEnable */);
     3811        ichac97R3StreamReset(pThis, &pThis->aStreams[i]);
     3812    }
    38193813
    38203814    /*
     
    38273821    AudioMixerSinkReset(pThis->pSinkMicIn);
    38283822    AudioMixerSinkReset(pThis->pSinkOut);
    3829 
    3830     /*
    3831      * Stop the timer, if any.
    3832      */
    3833     ichac97R3TimerStop(pThis);
    3834 
    3835     pThis->cStreamsActive = 0;
    38363823}
    38373824
     
    40964083    PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
    40974084    pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
    4098     pThis->pTimerRC  = TMTimerRCPtr(pThis->pTimerR3);
     4085
     4086    for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
     4087        pThis->pTimerRC[i] = TMTimerRCPtr(pThis->pTimerR3[i]);
    40994088}
    41004089
     
    43224311         * Create all hardware streams.
    43234312         */
    4324         rc = ichac97R3StreamCreate(pThis, &pThis->StreamLineIn, AC97SOUNDSOURCE_PI_INDEX);
    4325         if (RT_SUCCESS(rc))
    4326         {
    4327             rc = ichac97R3StreamCreate(pThis, &pThis->StreamMicIn, AC97SOUNDSOURCE_MC_INDEX);
     4313        for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
     4314        {
     4315            int rc2 = ichac97R3StreamCreate(pThis, &pThis->aStreams[i], i /* SD# */);
     4316            AssertRC(rc2);
    43284317            if (RT_SUCCESS(rc))
    4329                 rc = ichac97R3StreamCreate(pThis, &pThis->StreamOut, AC97SOUNDSOURCE_PO_INDEX);
     4318                rc = rc2;
    43304319        }
    43314320
     
    44334422    if (RT_SUCCESS(rc))
    44344423    {
    4435         /* Create the emulation timer.
    4436          *
    4437          * Note:  Use TMCLOCK_VIRTUAL_SYNC here, as the guest's AC'97 driver
    4438          *        relies on exact (virtual) DMA timing and uses DMA Position Buffers
    4439          *        instead of the LPIB registers.
    4440          */
    4441         rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, ichac97R3Timer, pThis,
    4442                                     TMTIMER_FLAGS_NO_CRIT_SECT, "AC'97 Timer", &pThis->pTimerR3);
    4443         AssertRCReturn(rc, rc);
    4444         pThis->pTimerR0 = TMTimerR0Ptr(pThis->pTimerR3);
    4445         pThis->pTimerRC = TMTimerRCPtr(pThis->pTimerR3);
    4446 
    4447         /* Use our own critcal section for the device timer.
    4448          * That way we can control more fine-grained when to lock what. */
    4449         rc = TMR3TimerSetCritSect(pThis->pTimerR3, &pThis->CritSect);
    4450         AssertRCReturn(rc, rc);
    4451 
    4452         pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimerR3) / pThis->uTimerHz;
    4453         pThis->uTimerTS    = TMTimerGet(pThis->pTimerR3);
    4454         LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, pThis->uTimerHz));
     4424        for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)
     4425        {
     4426            /* Create the emulation timer (per stream).
     4427             *
     4428             * Note:  Use TMCLOCK_VIRTUAL_SYNC here, as the guest's AC'97 driver
     4429             *        relies on exact (virtual) DMA timing and uses DMA Position Buffers
     4430             *        instead of the LPIB registers.
     4431             */
     4432            char szTimer[16];
     4433            RTStrPrintf2(szTimer, sizeof(szTimer), "AC97SD%i", i);
     4434
     4435            rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, ichac97R3Timer, &pThis->aStreams[i],
     4436                                        TMTIMER_FLAGS_NO_CRIT_SECT, szTimer, &pThis->pTimerR3[i]);
     4437            AssertRCReturn(rc, rc);
     4438            pThis->pTimerR0[i] = TMTimerR0Ptr(pThis->pTimerR3[i]);
     4439            pThis->pTimerRC[i] = TMTimerRCPtr(pThis->pTimerR3[i]);
     4440
     4441            /* Use our own critcal section for the device timer.
     4442             * That way we can control more fine-grained when to lock what. */
     4443            rc = TMR3TimerSetCritSect(pThis->pTimerR3[i], &pThis->CritSect);
     4444            AssertRCReturn(rc, rc);
     4445        }
    44554446    }
    44564447
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