VirtualBox

Changeset 69919 in vbox for trunk/src/VBox/Devices/Audio


Ignore:
Timestamp:
Dec 4, 2017 2:00:05 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
119399
Message:

Audio/HDA: Integrated fixes up to r119397 from 5.1-audio-timing branch into trunk.

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

Legend:

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

    r69719 r69919  
    229229static int hdaRegWriteCORBRP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
    230230static int hdaRegWriteCORBCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
     231static int hdaRegWriteCORBSIZE(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
    231232static int hdaRegWriteCORBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
     233static int hdaRegWriteRINTCNT(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
    232234static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
    233235static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
     
    281283 * @{
    282284 */
    283 #if !defined(VBOX_WITH_AUDIO_HDA_CALLBACKS) && defined(IN_RING3)
    284 static int           hdaTimerMaybeStart(PHDASTATE pThis);
    285 static int           hdaTimerMaybeStop(PHDASTATE pThis);
    286 static void          hdaTimerMain(PHDASTATE pThis);
     285#ifdef IN_RING3
     286static void hdaTimerMain(PHDASTATE pThis);
    287287#endif
    288288/** @} */
     
    351351    { 0x00044, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, HDA_RD_FLAG_NONE, hdaRegReadU32   , hdaRegWriteBase    , HDA_REG_IDX(CORBUBASE)    }, /* CORB Upper Base Address */
    352352    { 0x00048, 0x00002, 0x000000FF, 0x000000FF, HDA_RD_FLAG_NONE, hdaRegReadU16   , hdaRegWriteCORBWP  , HDA_REG_IDX(CORBWP)       }, /* CORB Write Pointer */
    353     { 0x0004A, 0x00002, 0x000080FF, 0x000080FF, HDA_RD_FLAG_NONE, hdaRegReadU16   , hdaRegWriteCORBRP  , HDA_REG_IDX(CORBRP)       }, /* CORB Read Pointer */
     353    { 0x0004A, 0x00002, 0x000080FF, 0x00008000, HDA_RD_FLAG_NONE, hdaRegReadU16   , hdaRegWriteCORBRP  , HDA_REG_IDX(CORBRP)       }, /* CORB Read Pointer */
    354354    { 0x0004C, 0x00001, 0x00000003, 0x00000003, HDA_RD_FLAG_NONE, hdaRegReadU8    , hdaRegWriteCORBCTL , HDA_REG_IDX(CORBCTL)      }, /* CORB Control */
    355355    { 0x0004D, 0x00001, 0x00000001, 0x00000001, HDA_RD_FLAG_NONE, hdaRegReadU8    , hdaRegWriteCORBSTS , HDA_REG_IDX(CORBSTS)      }, /* CORB Status */
    356     { 0x0004E, 0x00001, 0x000000F3, 0x00000000, HDA_RD_FLAG_NONE, hdaRegReadU8    , hdaRegWriteUnimpl  , HDA_REG_IDX(CORBSIZE)     }, /* CORB Size */
     356    { 0x0004E, 0x00001, 0x000000F3, 0x00000003, HDA_RD_FLAG_NONE, hdaRegReadU8    , hdaRegWriteCORBSIZE, HDA_REG_IDX(CORBSIZE)     }, /* CORB Size */
    357357    { 0x00050, 0x00004, 0xFFFFFF80, 0xFFFFFF80, HDA_RD_FLAG_NONE, hdaRegReadU32   , hdaRegWriteBase    , HDA_REG_IDX(RIRBLBASE)    }, /* RIRB Lower Base Address */
    358358    { 0x00054, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, HDA_RD_FLAG_NONE, hdaRegReadU32   , hdaRegWriteBase    , HDA_REG_IDX(RIRBUBASE)    }, /* RIRB Upper Base Address */
    359359    { 0x00058, 0x00002, 0x000000FF, 0x00008000, HDA_RD_FLAG_NONE, hdaRegReadU8    , hdaRegWriteRIRBWP  , HDA_REG_IDX(RIRBWP)       }, /* RIRB Write Pointer */
    360     { 0x0005A, 0x00002, 0x000000FF, 0x000000FF, HDA_RD_FLAG_NONE, hdaRegReadU16   , hdaRegWriteU16    , HDA_REG_IDX(RINTCNT)      }, /* Response Interrupt Count */
     360    { 0x0005A, 0x00002, 0x000000FF, 0x000000FF, HDA_RD_FLAG_NONE, hdaRegReadU16   , hdaRegWriteRINTCNT , HDA_REG_IDX(RINTCNT)      }, /* Response Interrupt Count */
    361361    { 0x0005C, 0x00001, 0x00000007, 0x00000007, HDA_RD_FLAG_NONE, hdaRegReadU8    , hdaRegWriteU8      , HDA_REG_IDX(RIRBCTL)      }, /* RIRB Control */
    362362    { 0x0005D, 0x00001, 0x00000005, 0x00000005, HDA_RD_FLAG_NONE, hdaRegReadU8    , hdaRegWriteRIRBSTS , HDA_REG_IDX(RIRBSTS)      }, /* RIRB Status */
     
    436436    SSMFIELD_ENTRY(HDASTREAMSTATE, uCurBDLE),
    437437    SSMFIELD_ENTRY(HDASTREAMSTATE, fInReset),
    438     SSMFIELD_ENTRY(HDASTREAMSTATE, uTimerTS),
     438    SSMFIELD_ENTRY(HDASTREAMSTATE, tsTransferNext),
    439439    SSMFIELD_ENTRY_TERM()
    440440};
     
    723723    if (fLocal)
    724724    {
    725         Assert((HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA));
    726         Assert(pThis->u64CORBBase);
    727         AssertPtr(pThis->pu32CorbBuf);
    728         Assert(pThis->cbCorbBuf);
    729 
    730         rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pThis->u64CORBBase, pThis->pu32CorbBuf, pThis->cbCorbBuf);
    731         if (RT_FAILURE(rc))
    732             AssertRCReturn(rc, rc);
     725        if (pThis->u64CORBBase)
     726        {
     727            AssertPtr(pThis->pu32CorbBuf);
     728            Assert(pThis->cbCorbBuf);
     729
     730            rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pThis->u64CORBBase, pThis->pu32CorbBuf, pThis->cbCorbBuf);
     731            if (RT_FAILURE(rc))
     732                AssertRCReturn(rc, rc);
     733        }
    733734    }
    734735    else
    735736    {
    736         Assert((HDA_REG(pThis, RIRBCTL) & HDA_RIRBCTL_RDMAEN));
    737         rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pThis->u64RIRBBase, pThis->pu64RirbBuf, pThis->cbRirbBuf);
    738         if (RT_FAILURE(rc))
    739             AssertRCReturn(rc, rc);
     737        if (pThis->u64RIRBBase)
     738        {
     739            AssertPtr(pThis->pu64RirbBuf);
     740            Assert(pThis->cbRirbBuf);
     741
     742            rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pThis->u64RIRBBase, pThis->pu64RirbBuf, pThis->cbRirbBuf);
     743            if (RT_FAILURE(rc))
     744                AssertRCReturn(rc, rc);
     745        }
    740746    }
    741747
     
    791797static int hdaCORBCmdProcess(PHDASTATE pThis)
    792798{
    793     int rc = hdaCmdSync(pThis, true /* Sync from guest */);
    794     AssertRCReturn(rc, rc);
    795 
    796799    uint8_t corbRp = HDA_REG(pThis, CORBRP);
    797800    uint8_t corbWp = HDA_REG(pThis, CORBWP);
     
    800803    Log3Func(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", corbRp, corbWp, rirbWp));
    801804
     805    if (!(HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA))
     806    {
     807        LogFunc(("CORB DMA not active, skipping\n"));
     808        return VINF_SUCCESS;
     809    }
     810
     811    Assert(pThis->cbCorbBuf);
     812
     813    int rc = hdaCmdSync(pThis, true /* Sync from guest */);
     814    AssertRCReturn(rc, rc);
     815
     816    uint16_t cIntCnt = HDA_REG(pThis, RINTCNT) & 0xff;
     817
     818    if (!cIntCnt) /* 0 means 256 interrupts. */
     819        cIntCnt = HDA_MAX_RINTCNT;
     820
     821    Log3Func(("START CORB(RP:%x, WP:%x) RIRBWP:%x, RINTCNT:%RU8/%RU8\n",
     822              corbRp, corbWp, rirbWp, pThis->u16RespIntCnt, cIntCnt));
     823
    802824    while (corbRp != corbWp)
    803825    {
    804         corbRp = (corbRp + 1) % HDA_CORB_SIZE; /* Advance +1 as the first command(s) are at CORBWP + 1. */
    805 
     826        corbRp = (corbRp + 1) % (pThis->cbCorbBuf / HDA_CORB_ELEMENT_SIZE); /* Advance +1 as the first command(s) are at CORBWP + 1. */
     827
     828        uint32_t uCmd  = pThis->pu32CorbBuf[corbRp];
    806829        uint64_t uResp = 0;
    807         uint32_t uCmd = pThis->pu32CorbBuf[corbRp];
    808830
    809831        rc = pThis->pCodec->pfnLookup(pThis->pCodec, HDA_CODEC_CMD(uCmd, 0 /* Codec index */), &uResp);
     
    811833            LogFunc(("Codec lookup failed with rc=%Rrc\n", rc));
    812834
    813         LogFunc(("verb:%08x -> %016lx\n", uCmd, uResp));
     835        Log3Func(("Codec verb %08x -> response %016lx\n", uCmd, uResp));
    814836
    815837        if (   (uResp & CODEC_RESPONSE_UNSOLICITED)
     
    828850
    829851        pThis->u16RespIntCnt++;
    830         if (pThis->u16RespIntCnt > HDA_MAX_RINTCNT) /* Make sure that the guest can't hang the host. */
    831         {
    832             LogRel(("HDA: Maximum response interrupt count (%d) reached, bailing out\n", HDA_MAX_RINTCNT));
    833             pThis->u16RespIntCnt = HDA_MAX_RINTCNT;
    834             break;
    835         }
    836     }
     852
     853        bool fSendInterrupt = false;
     854
     855        if (pThis->u16RespIntCnt == cIntCnt) /* Response interrupt count reached? */
     856        {
     857            pThis->u16RespIntCnt = 0; /* Reset internal interrupt response counter. */
     858
     859            Log3Func(("Response interrupt count reached (%RU16)\n", pThis->u16RespIntCnt));
     860            fSendInterrupt = true;
     861
     862        }
     863        else if (corbRp == corbWp) /* Did we reach the end of the current command buffer? */
     864        {
     865            Log3Func(("Command buffer empty\n"));
     866            fSendInterrupt = true;
     867        }
     868
     869        if (fSendInterrupt)
     870        {
     871            if (HDA_REG(pThis, RIRBCTL) & HDA_RIRBCTL_RINTCTL) /* Response Interrupt Control (RINTCTL) enabled? */
     872            {
     873                HDA_REG(pThis, RIRBSTS) |= HDA_RIRBSTS_RINTFL;
     874
     875#ifndef DEBUG
     876                rc = hdaProcessInterrupt(pThis);
     877#else
     878                rc = hdaProcessInterrupt(pThis, __FUNCTION__);
     879#endif
     880            }
     881        }
     882    }
     883
     884    Log3Func(("END CORB(RP:%x, WP:%x) RIRBWP:%x, RINTCNT:%RU8/%RU8\n",
     885              corbRp, corbWp, rirbWp, pThis->u16RespIntCnt, cIntCnt));
    837886
    838887    HDA_REG(pThis, CORBRP) = corbRp;
     
    841890    rc = hdaCmdSync(pThis, false /* Sync to guest */);
    842891    AssertRCReturn(rc, rc);
    843 
    844     Log3Func(("CORB(RP:%x, WP:%x) RIRBWP:%x, uRespIntCnt=%RU16\n", corbRp, corbWp, rirbWp, pThis->u16RespIntCnt));
    845 
    846     if (pThis->u16RespIntCnt)
    847     {
    848         if (HDA_REG(pThis, RIRBCTL) & HDA_RIRBCTL_RINTCTL) /* Response Interrupt Control (RINTCTL) enabled? */
    849         {
    850             HDA_REG(pThis, RIRBSTS) |= HDA_RIRBSTS_RINTFL;
    851             HDA_REG(pThis, RINTCNT)  = RT_LO_U8(pThis->u16RespIntCnt);
    852 
    853 #ifndef DEBUG
    854             rc = hdaProcessInterrupt(pThis);
    855 #else
    856             rc = hdaProcessInterrupt(pThis, __FUNCTION__);
    857 #endif
    858             pThis->u16RespIntCnt--;
    859         }
    860         else /* Not enabled -- just reset our internal counter. */
    861             pThis->u16RespIntCnt = 0;
    862     }
    863892
    864893    if (RT_FAILURE(rc))
     
    10891118static int hdaRegWriteCORBRP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
    10901119{
    1091     RT_NOREF_PV(iReg);
     1120    RT_NOREF(iReg);
    10921121
    10931122    DEVHDA_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
    10941123
    10951124    if (u32Value & HDA_CORBRP_RST)
     1125    {
     1126        /* Do a CORB reset. */
     1127        if (pThis->cbCorbBuf)
     1128        {
     1129            Assert(pThis->pu32CorbBuf);
     1130            RT_BZERO((void *)pThis->pu32CorbBuf, pThis->cbCorbBuf);
     1131        }
     1132
     1133        LogRel2(("HDA: CORB reset\n"));
     1134
    10961135        HDA_REG(pThis, CORBRP) = HDA_CORBRP_RST;    /* Clears the pointer. */
     1136    }
    10971137    else
    10981138        HDA_REG(pThis, CORBRP) &= ~HDA_CORBRP_RST;  /* Only CORBRP_RST bit is writable. */
     
    11051145{
    11061146#ifdef IN_RING3
     1147    DEVHDA_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
     1148
    11071149    int rc = hdaRegWriteU8(pThis, iReg, u32Value);
    11081150    AssertRC(rc);
    11091151
    1110     DEVHDA_LOCK(pThis);
    1111 
    1112     if (   (uint8_t)HDA_REG(pThis, CORBWP) != (uint8_t)HDA_REG(pThis, CORBRP)
    1113         && (HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA))
     1152    if (HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA) /* Start DMA engine. */
    11141153    {
    11151154        rc = hdaCORBCmdProcess(pThis);
    11161155    }
     1156    else
     1157        LogFunc(("CORB DMA not running, skipping\n"));
    11171158
    11181159    DEVHDA_UNLOCK(pThis);
    1119 
    11201160    return rc;
    11211161#else
    1122     RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
     1162    RT_NOREF(pThis, iReg, u32Value);
     1163    return VINF_IOM_R3_MMIO_WRITE;
     1164#endif
     1165}
     1166
     1167static int hdaRegWriteCORBSIZE(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
     1168{
     1169#ifdef IN_RING3
     1170    RT_NOREF(iReg);
     1171
     1172    DEVHDA_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
     1173
     1174    if (HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA) /* Ignore request if CORB DMA engine is (still) running. */
     1175    {
     1176        LogFunc(("CORB DMA is (still) running, skipping\n"));
     1177
     1178        DEVHDA_UNLOCK(pThis);
     1179        return VINF_SUCCESS;
     1180    }
     1181
     1182    u32Value = (u32Value & HDA_CORBSIZE_SZ);
     1183
     1184    uint16_t cEntries = HDA_CORB_SIZE; /* Set default. */
     1185
     1186    switch (u32Value)
     1187    {
     1188        case 0: /* 8 byte; 2 entries. */
     1189            cEntries = 2;
     1190            break;
     1191
     1192        case 1: /* 64 byte; 16 entries. */
     1193            cEntries = 16;
     1194            break;
     1195
     1196        case 2: /* 1 KB; 256 entries. */
     1197            /* Use default size. */
     1198            break;
     1199
     1200        default:
     1201            LogRel(("HDA: Guest tried to set an invalid CORB size (0x%x), keeping default\n", u32Value));
     1202            u32Value = 2;
     1203            /* Use default size. */
     1204            break;
     1205    }
     1206
     1207    uint32_t cbCorbBuf = cEntries * sizeof(uint32_t);
     1208
     1209    if (cbCorbBuf != pThis->cbCorbBuf)
     1210    {
     1211        if (pThis->pu32CorbBuf)
     1212        {
     1213            RTMemFree(pThis->pu32CorbBuf);
     1214            pThis->pu32CorbBuf = NULL;
     1215        }
     1216
     1217        if (cbCorbBuf)
     1218        {
     1219            Assert(cbCorbBuf % sizeof(uint32_t) == 0);
     1220
     1221            pThis->pu32CorbBuf = (uint32_t *)RTMemAllocZ(cbCorbBuf);
     1222            pThis->cbCorbBuf   = cbCorbBuf;
     1223        }
     1224    }
     1225
     1226    LogFunc(("CORB buffer size is now %RU32 bytes (%u entries)\n", pThis->cbCorbBuf, pThis->cbCorbBuf / HDA_CORB_ELEMENT_SIZE));
     1227
     1228    HDA_REG(pThis, CORBSIZE) = u32Value;
     1229
     1230    DEVHDA_UNLOCK(pThis);
     1231    return VINF_SUCCESS;
     1232#else
     1233    RT_NOREF(pThis, iReg, u32Value);
    11231234    return VINF_IOM_R3_MMIO_WRITE;
    11241235#endif
     
    11351246
    11361247    DEVHDA_UNLOCK(pThis);
    1137 
    11381248    return VINF_SUCCESS;
    11391249}
     
    11421252{
    11431253#ifdef IN_RING3
     1254    DEVHDA_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
     1255
    11441256    int rc = hdaRegWriteU16(pThis, iReg, u32Value);
    1145     AssertRCReturn(rc, rc);
    1146 
    1147     DEVHDA_LOCK(pThis);
    1148 
    1149     if ((uint8_t)HDA_REG(pThis, CORBWP) == (uint8_t)HDA_REG(pThis, CORBRP))
    1150     {
    1151         DEVHDA_UNLOCK(pThis);
    1152         return VINF_SUCCESS;
    1153     }
    1154 
    1155     if (!(HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA))
    1156     {
    1157         DEVHDA_UNLOCK(pThis);
    1158         return VINF_SUCCESS;
    1159     }
     1257    if (RT_FAILURE(rc))
     1258        AssertRCReturn(rc, rc);
    11601259
    11611260    rc = hdaCORBCmdProcess(pThis);
    11621261
    11631262    DEVHDA_UNLOCK(pThis);
    1164 
    11651263    return rc;
    1166 #else  /* !IN_RING3 */
    1167     RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
     1264#else
     1265    RT_NOREF(pThis, iReg, u32Value);
    11681266    return VINF_IOM_R3_MMIO_WRITE;
    1169 #endif /* IN_RING3 */
     1267#endif
    11701268}
    11711269
     
    13061404
    13071405            /* Enable/disable the stream. */
    1308             hdaStreamEnable(pStream, fRun /* fEnable */);
     1406            rc2 = hdaStreamEnable(pStream, fRun /* fEnable */);
     1407            AssertRC(rc2);
    13091408
    13101409            if (fRun)
    13111410            {
     1411                /* Keep track of running streams. */
     1412                pThis->cStreamsActive++;
     1413
    13121414                /* (Re-)init the stream's period. */
    13131415                hdaStreamPeriodInit(&pStream->State.Period,
     
    13161418                /* Begin a new period for this stream. */
    13171419                rc2 = hdaStreamPeriodBegin(&pStream->State.Period, hdaWalClkGetCurrent(pThis)/* Use current wall clock time */);
     1420                AssertRC(rc2);
     1421
     1422                rc2 = hdaTimerSet(pThis, TMTimerGet(pThis->pTimer) + pStream->State.cTransferTicks, false /* fForce */);
    13181423                AssertRC(rc2);
    13191424            }
    13201425            else
    13211426            {
     1427                /* Keep track of running streams. */
     1428                Assert(pThis->cStreamsActive);
     1429                if (pThis->cStreamsActive)
     1430                    pThis->cStreamsActive--;
     1431
    13221432                /* Make sure to (re-)schedule outstanding (delayed) interrupts. */
    13231433                hdaReschedulePendingInterrupts(pThis);
     
    13321442            /* Make sure to leave the lock before (eventually) starting the timer. */
    13331443            hdaStreamUnlock(pStream);
    1334 
    1335 # ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    1336             /* See if we need to start or stop the timer. */
    1337             if (!fRun)
    1338                 hdaTimerMaybeStop(pThis);
    1339             else
    1340                 hdaTimerMaybeStart(pThis);
    1341 # endif
    13421444        }
    13431445    }
     
    13581460{
    13591461#ifdef IN_RING3
    1360     DEVHDA_LOCK(pThis);
     1462    DEVHDA_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
    13611463
    13621464    PHDASTREAM pStream = hdaGetStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, STS, iReg));
     
    13661468                         HDA_SD_NUM_FROM_REG(pThis, STS, iReg), u32Value));
    13671469
    1368         DEVHDA_UNLOCK(pThis);
     1470        DEVHDA_UNLOCK_BOTH(pThis);
    13691471        return hdaRegWriteU16(pThis, iReg, u32Value);
    13701472    }
     
    13911493        if (hdaStreamPeriodIsComplete(pPeriod))
    13921494        {
     1495            /* Make sure to try to update the WALCLK register if a period is complete.
     1496             * Use the maximum WALCLK value all (active) streams agree to. */
     1497            const uint64_t uWalClkMax = hdaWalClkGetMax(pThis);
     1498            if (uWalClkMax > hdaWalClkGetCurrent(pThis))
     1499                hdaWalClkSet(pThis, uWalClkMax, false /* fForce */);
     1500
    13931501            hdaStreamPeriodEnd(pPeriod);
    13941502
     
    13981506
    13991507        hdaStreamPeriodUnlock(pPeriod); /* Unlock before processing interrupt. */
    1400 
    1401         if (fNeedsInterrupt)
    1402         {
     1508    }
     1509
    14031510#ifndef DEBUG
    1404             hdaProcessInterrupt(pThis);
     1511    hdaProcessInterrupt(pThis);
    14051512#else
    1406             hdaProcessInterrupt(pThis, __FUNCTION__);
    1407 #endif
    1408         }
    1409     }
    1410 
    1411     DEVHDA_UNLOCK(pThis);
     1513    hdaProcessInterrupt(pThis, __FUNCTION__);
     1514#endif
     1515
     1516    const uint64_t tsNow = TMTimerGet(pThis->pTimer);
     1517    Assert(tsNow >= pStream->State.tsTransferLast);
     1518
     1519    const uint64_t cTicksElapsed     = tsNow - pStream->State.tsTransferLast;
     1520    const uint64_t cTicksTransferred = pStream->State.cbTransferProcessed * pStream->State.cTicksPerByte;
     1521
     1522    uint64_t cTicksToNext = pStream->State.cTransferTicks;
     1523
     1524    Log3Func(("[SD%RU8] cTicksElapsed=%RU64, cTicksTransferred=%RU64, cTicksToNext=%RU64\n",
     1525              pStream->u8SD, cTicksElapsed, cTicksTransferred, cTicksToNext));
     1526
     1527    Log3Func(("[SD%RU8] cbTransferProcessed=%RU32, cbTransferChunk=%RU32, cbTransferSize=%RU32\n",
     1528              pStream->u8SD, pStream->State.cbTransferProcessed, pStream->State.cbTransferChunk, pStream->State.cbTransferSize));
     1529
     1530    if (cTicksElapsed <= cTicksToNext)
     1531    {
     1532        cTicksToNext = cTicksToNext - cTicksElapsed;
     1533    }
     1534    else /* Catch up. */
     1535    {
     1536        Log3Func(("[SD%RU8] Warning: Lagging behind (%RU64 ticks elapsed, maximum allowed is %RU64)\n",
     1537                 pStream->u8SD, cTicksElapsed, cTicksToNext));
     1538
     1539        LogRelMax2(64, ("HDA: Stream #%RU8 interrupt lagging behind (expected %uus, got %uus), trying to catch up ...\n",
     1540                        pStream->u8SD,
     1541                        (TMTimerGetFreq(pThis->pTimer) / pThis->u16TimerHz) / 1000, (tsNow - pStream->State.tsTransferLast) / 1000));
     1542
     1543        cTicksToNext = 0;
     1544    }
     1545
     1546    Log3Func(("[SD%RU8] -> cTicksToNext=%RU64\n", pStream->u8SD, cTicksToNext));
     1547
     1548    /* Reset processed data counter. */
     1549    pStream->State.cbTransferProcessed = 0;
     1550
     1551    /* Re-arm the timer. */
     1552    hdaTimerSet(pThis, tsNow + cTicksToNext, false /* fForce */);
     1553
     1554    DEVHDA_UNLOCK_BOTH(pThis);
    14121555    return VINF_SUCCESS;
    14131556#else /* IN_RING3 */
     
    19982141static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
    19992142{
    2000     RT_NOREF_PV(iReg);
     2143    RT_NOREF(iReg);
    20012144
    20022145    DEVHDA_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
    20032146
     2147    if (HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA) /* Ignore request if CORB DMA engine is (still) running. */
     2148    {
     2149        LogFunc(("CORB DMA (still) running, skipping\n"));
     2150
     2151        DEVHDA_UNLOCK(pThis);
     2152        return VINF_SUCCESS;
     2153    }
     2154
    20042155    if (u32Value & HDA_RIRBWP_RST)
     2156    {
     2157        /* Do a RIRB reset. */
     2158        if (pThis->cbRirbBuf)
     2159        {
     2160            Assert(pThis->pu64RirbBuf);
     2161            RT_BZERO((void *)pThis->pu64RirbBuf, pThis->cbRirbBuf);
     2162        }
     2163
     2164        LogRel2(("HDA: RIRB reset\n"));
     2165
    20052166        HDA_REG(pThis, RIRBWP) = 0;
     2167    }
    20062168
    20072169    DEVHDA_UNLOCK(pThis);
     
    20092171    /* The remaining bits are O, see 6.2.22. */
    20102172    return VINF_SUCCESS;
     2173}
     2174
     2175static int hdaRegWriteRINTCNT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
     2176{
     2177    DEVHDA_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
     2178
     2179    if (HDA_REG(pThis, CORBCTL) & HDA_CORBCTL_DMA) /* Ignore request if CORB DMA engine is (still) running. */
     2180    {
     2181        LogFunc(("CORB DMA is (still) running, skipping\n"));
     2182
     2183        DEVHDA_UNLOCK(pThis);
     2184        return VINF_SUCCESS;
     2185    }
     2186
     2187    RT_NOREF(iReg);
     2188
     2189    int rc = hdaRegWriteU16(pThis, iReg, u32Value);
     2190    AssertRC(rc);
     2191
     2192    LogFunc(("Response interrupt count is now %RU8\n", HDA_REG(pThis, RINTCNT) & 0xFF));
     2193
     2194    DEVHDA_UNLOCK(pThis);
     2195    return rc;
    20112196}
    20122197
     
    25152700}
    25162701
    2517 #ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    2518 /**
    2519  * Starts the internal audio device timer.
    2520  *
    2521  * @return  IPRT status code.
    2522  * @param   pThis               HDA state.
    2523  */
    2524 static int hdaTimerStart(PHDASTATE pThis)
    2525 {
    2526     LogFlowFuncEnter();
    2527 
    2528     DEVHDA_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
    2529 
    2530     AssertPtr(pThis->pTimer);
    2531 
    2532     if (!pThis->fTimerActive)
    2533     {
    2534         LogRel2(("HDA: Starting transfers\n"));
    2535 
    2536         pThis->fTimerActive  = true;
    2537         pThis->tsTimerExpire = TMTimerGet(pThis->pTimer) + pThis->cTimerTicks; /* Update current time timestamp. */
    2538 
    2539         /* Start transfers. */
    2540         hdaTimerMain(pThis);
    2541     }
    2542 
    2543     DEVHDA_UNLOCK_BOTH(pThis);
    2544 
    2545     return VINF_SUCCESS;
    2546 }
    2547 
    2548 /**
    2549  * Starts the internal audio device timer (if not started yet).
    2550  *
    2551  * @return  IPRT status code.
    2552  * @param   pThis               HDA state.
    2553  */
    2554 static int hdaTimerMaybeStart(PHDASTATE pThis)
    2555 {
    2556     LogFlowFuncEnter();
    2557 
    2558     if (!pThis->pTimer)
    2559         return VERR_WRONG_ORDER;
    2560 
    2561     pThis->cStreamsActive++;
    2562 
    2563     /* Only start the timer at the first active stream. */
    2564     if (pThis->cStreamsActive == 1)
    2565         return hdaTimerStart(pThis);
    2566 
    2567     return VINF_SUCCESS;
    2568 }
    2569 
    2570 /**
    2571  * Stops the internal audio device timer.
    2572  *
    2573  * @return  IPRT status code.
    2574  * @param   pThis               HDA state.
    2575  */
    2576 static int hdaTimerStop(PHDASTATE pThis)
    2577 {
    2578     LogFlowFuncEnter();
    2579 
    2580     if (!pThis->pTimer) /* Only can happen on device construction time, so no locking needed here. */
    2581         return VINF_SUCCESS;
    2582 
    2583     DEVHDA_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);
    2584 
    2585     if (pThis->fTimerActive)
    2586     {
    2587         LogRel2(("HDA: Stopping transfers ...\n"));
    2588 
    2589         pThis->fTimerActive = false;
    2590 
    2591         /* Note: Do not stop the timer via TMTimerStop() here, as there still might
    2592          *       be queued audio data which needs to be handled (e.g. played back) first
    2593          *       before actually stopping the timer for good. */
    2594     }
    2595 
    2596     DEVHDA_UNLOCK_BOTH(pThis);
    2597 
    2598     return VINF_SUCCESS;
    2599 }
    2600 
    2601 /**
    2602  * Decreases the active HDA streams count by one and
    2603  * then checks if the internal audio device timer can be
    2604  * stopped.
    2605  *
    2606  * @return  IPRT status code.
    2607  * @param   pThis               HDA state.
    2608  */
    2609 static int hdaTimerMaybeStop(PHDASTATE pThis)
    2610 {
    2611     LogFlowFuncEnter();
    2612 
    2613     if (!pThis->pTimer)
    2614         return VERR_WRONG_ORDER;
    2615 
    2616     if (pThis->cStreamsActive) /* Disable can be called mupltiple times. */
    2617     {
    2618         pThis->cStreamsActive--;
    2619 
    2620         if (pThis->cStreamsActive == 0)
    2621             return hdaTimerStop(pThis);
    2622     }
    2623 
    2624     return VINF_SUCCESS;
    2625 }
    2626 
    26272702/**
    26282703 * Main routine for the device timer.
     
    26382713    DEVHDA_LOCK_BOTH_RETURN_VOID(pThis);
    26392714
     2715    /* Do all transfers from/to DMA. */
     2716    hdaDoTransfers(pThis);
     2717
    26402718    /* Flag indicating whether to kick the timer again for a
    26412719     * new data processing round. */
    2642     bool fKickTimer = false;
    2643 
    2644     hdaDoTransfers(pThis);
     2720    bool fSinksActive = false;
    26452721
    26462722    /* Do we need to kick the timer again? */
     
    26562732        )
    26572733    {
    2658         fKickTimer = true;
    2659     }
    2660 
    2661     if (   ASMAtomicReadBool(&pThis->fTimerActive)
    2662         || fKickTimer)
    2663     {
    2664         /* Kick the timer again. */
    2665         pThis->tsTimerExpire += pThis->cTimerTicks;
    2666 
    2667         TMTimerSet(pThis->pTimer, pThis->tsTimerExpire);
    2668     }
    2669     else
    2670         LogRel2(("HDA: Stopped transfers\n"));
     2734        fSinksActive = true;
     2735    }
     2736
     2737    bool fTimerScheduled = false;
     2738    if (   hdaStreamTransferIsScheduled(hdaGetStreamFromSink(pThis, &pThis->SinkFront))
     2739#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
     2740        || hdaStreamTransferIsScheduled(hdaGetStreamFromSink(pThis, &pThis->SinkMicIn))
     2741#endif
     2742        || hdaStreamTransferIsScheduled(hdaGetStreamFromSink(pThis, &pThis->SinkLineIn)))
     2743    {
     2744        fTimerScheduled = true;
     2745    }
     2746
     2747    Log3Func(("fSinksActive=%RTbool, fTimerScheduled=%RTbool\n", fSinksActive, fTimerScheduled));
     2748
     2749    if (    fSinksActive
     2750        && !fTimerScheduled)
     2751    {
     2752        hdaTimerSet(pThis, TMTimerGet(pThis->pTimer) + TMTimerGetFreq(pThis->pTimer) / pThis->u16TimerHz, true /* fForce */);
     2753    }
    26712754
    26722755    DEVHDA_UNLOCK_BOTH(pThis);
     
    27272810            uint64_t cbWrittenHz = ASMAtomicReadU64(&pStreamDbg->cbWrittenHz);
    27282811
    2729             if (tsElapsedMs >= (1000 / HDA_TIMER_HZ))
     2812            if (tsElapsedMs >= (1000 / HDA_TIMER_HZ_DEFAULT))
    27302813            {
    27312814                LogFunc(("[SD%RU8] %RU32ms elapsed, cbWritten=%RU64, cWritten=%RU64 -- %RU32 bytes on average per time slot (%zums)\n",
    27322815                         pStream->u8SD, tsElapsedMs, cbWrittenHz, cWritesHz,
    2733                          ASMDivU64ByU32RetU32(cbWrittenHz, cWritesHz ? cWritesHz : 1), 1000 / HDA_TIMER_HZ));
     2816                         ASMDivU64ByU32RetU32(cbWrittenHz, cWritesHz ? cWritesHz : 1), 1000 / HDA_TIMER_HZ_DEFAULT));
    27342817
    27352818                pStreamDbg->tsWriteSlotBegin = tsNowNs;
     
    28172900    LogFlowFuncEnter();
    28182901
    2819 # ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    2820     /*
    2821      * Stop the timer, if any.
    2822      */
    2823     hdaTimerStop(pThis);
    2824 
    28252902    pThis->cStreamsActive = 0;
    2826 # endif
    2827 
    2828     memset(pThis->au32Regs, 0, sizeof(pThis->au32Regs));
    2829     /* See 6.2.1. */
    2830     HDA_REG(pThis, GCAP)     = HDA_MAKE_GCAP(HDA_MAX_SDO /* Ouput streams */,
    2831                                              HDA_MAX_SDI /* Input streams */,
    2832                                              0           /* Bidirectional output streams */,
    2833                                              0           /* Serial data out signals */,
    2834                                              1           /* 64-bit */);
    2835     HDA_REG(pThis, VMIN)     = 0x00;                     /* see 6.2.2 */
    2836     HDA_REG(pThis, VMAJ)     = 0x01;                     /* see 6.2.3 */
    2837     /* Announce the full 60 words output payload. */
    2838     HDA_REG(pThis, OUTPAY)   = 0x003C;                   /* see 6.2.4 */
    2839     /* Announce the full 29 words input payload. */
    2840     HDA_REG(pThis, INPAY)    = 0x001D;                   /* see 6.2.5 */
    2841     HDA_REG(pThis, CORBSIZE) = 0x42;                     /* see 6.2.1 */
    2842     HDA_REG(pThis, RIRBSIZE) = 0x42;                     /* see 6.2.1 */
     2903
     2904    HDA_REG(pThis, GCAP)     = HDA_MAKE_GCAP(HDA_MAX_SDO, HDA_MAX_SDI, 0, 0, 1); /* see 6.2.1 */
     2905    HDA_REG(pThis, VMIN)     = 0x00;                                             /* see 6.2.2 */
     2906    HDA_REG(pThis, VMAJ)     = 0x01;                                             /* see 6.2.3 */
     2907    HDA_REG(pThis, OUTPAY)   = 0x003C;                                           /* see 6.2.4 */
     2908    HDA_REG(pThis, INPAY)    = 0x001D;                                           /* see 6.2.5 */
     2909    HDA_REG(pThis, CORBSIZE) = 0x42; /* Up to 256 CORB entries                      see 6.2.1 */
     2910    HDA_REG(pThis, RIRBSIZE) = 0x42; /* Up to 256 RIRB entries                      see 6.2.1 */
    28432911    HDA_REG(pThis, CORBRP)   = 0x0;
     2912    HDA_REG(pThis, CORBWP)   = 0x0;
    28442913    HDA_REG(pThis, RIRBWP)   = 0x0;
    2845     HDA_REG(pThis, RINTCNT)  = 0x0;
     2914    /* Some guests (like Haiku) don't set RINTCNT explicitly but expect an interrupt after each
     2915     * RIRB response -- so initialize RINTCNT to 1 by default. */
     2916    HDA_REG(pThis, RINTCNT)  = 0x1;
    28462917
    28472918    /*
     
    28722943    }
    28732944
    2874     /*
     2945       /*
    28752946     * Set some sensible defaults for which HDA sinks
    28762947     * are connected to which stream number.
     
    29232994}
    29242995
    2925 
    29262996/**
    29272997 * Timer callback which handles the audio data transfers on a periodic basis.
     
    29423012}
    29433013
    2944 #else /* VBOX_WITH_AUDIO_HDA_CALLBACKS */
    2945 
    2946 static DECLCALLBACK(int) hdaCallbackInput(PDMAUDIOBACKENDCBTYPE enmType, void *pvCtx, size_t cbCtx, void *pvUser, size_t cbUser)
    2947 {
    2948     Assert(enmType == PDMAUDIOCALLBACKTYPE_INPUT);
    2949     AssertPtrReturn(pvCtx,  VERR_INVALID_POINTER);
    2950     AssertReturn(cbCtx,     VERR_INVALID_PARAMETER);
    2951     AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
    2952     AssertReturn(cbUser,    VERR_INVALID_PARAMETER);
    2953 
    2954     PHDACALLBACKCTX pCtx = (PHDACALLBACKCTX)pvCtx;
    2955     AssertReturn(cbCtx == sizeof(HDACALLBACKCTX), VERR_INVALID_PARAMETER);
    2956 
    2957     PPDMAUDIOCBDATA_DATA_INPUT pData = (PPDMAUDIOCBDATA_DATA_INPUT)pvUser;
    2958     AssertReturn(cbUser == sizeof(PDMAUDIOCBDATA_DATA_INPUT), VERR_INVALID_PARAMETER);
    2959 
    2960     return hdaStreamDoDMA(pCtx->pThis, PI_INDEX, UINT32_MAX, &pData->cbOutRead);
    2961 }
    2962 
    2963 static DECLCALLBACK(int) hdaCallbackOutput(PDMAUDIOBACKENDCBTYPE enmType, void *pvCtx, size_t cbCtx, void *pvUser, size_t cbUser)
    2964 {
    2965     Assert(enmType == PDMAUDIOCALLBACKTYPE_OUTPUT);
    2966     AssertPtrReturn(pvCtx,  VERR_INVALID_POINTER);
    2967     AssertReturn(cbCtx,     VERR_INVALID_PARAMETER);
    2968     AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
    2969     AssertReturn(cbUser,    VERR_INVALID_PARAMETER);
    2970 
    2971     PHDACALLBACKCTX pCtx = (PHDACALLBACKCTX)pvCtx;
    2972     AssertReturn(cbCtx == sizeof(HDACALLBACKCTX), VERR_INVALID_PARAMETER);
    2973 
    2974     PPDMAUDIOCBDATA_DATA_OUTPUT pData = (PPDMAUDIOCBDATA_DATA_OUTPUT)pvUser;
    2975     AssertReturn(cbUser == sizeof(PDMAUDIOCBDATA_DATA_OUTPUT), VERR_INVALID_PARAMETER);
    2976 
    2977     PHDASTATE pThis = pCtx->pThis;
    2978 
    2979     int rc = hdaStreamDoDMA(pCtx->pThis, PO_INDEX, UINT32_MAX, &pData->cbOutWritten);
    2980     if (   RT_SUCCESS(rc)
    2981         && pData->cbOutWritten)
    2982     {
    2983         PHDADRIVER pDrv;
    2984         RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
    2985         {
    2986             uint32_t cFramesPlayed;
    2987             int rc2 = pDrv->pConnector->pfnPlay(pDrv->pConnector, &cFramesPlayed);
    2988             LogFlowFunc(("LUN#%RU8: cFramesPlayed=%RU32, rc=%Rrc\n", pDrv->uLUN, cFramesPlayed, rc2));
    2989         }
    2990     }
    2991 }
    2992 #endif /* VBOX_WITH_AUDIO_HDA_CALLBACKS */
    2993 
    29943014/**
    29953015 * Main routine to perform the actual audio data transfers from the HDA streams
     
    30053025#endif
    30063026    PHDASTREAM pStreamFront   = hdaGetStreamFromSink(pThis, &pThis->SinkFront);
    3007 #ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
    3008     /** @todo See note below. */
    3009 #endif
    30103027
    30113028    hdaStreamUpdate(pStreamFront,  true /* fInTimer */);
     
    35343551    int rc = VINF_SUCCESS;
    35353552
    3536     bool fStartTimer = false; /* Whether to resume the device timer. */
     3553    uint64_t tsExpire = 0; /* Timestamp of new timer expiration time / Whether to resume the device timer. */
    35373554
    35383555    /*
     
    35573574                hdaStreamAsyncIOEnable(pStream, true /* fEnable */);
    35583575#endif
    3559                 /* (Re-)initialize the stream with current values. */
    3560                 rc2 = hdaStreamInit(pStream, pStream->u8SD);
    3561                 AssertRC(rc2);
    3562 
    35633576                /* Resume the stream's period. */
    35643577                hdaStreamPeriodResume(&pStream->State.Period);
     
    35763589                hdaStreamRegisterDMAHandlers(pThis, pStream);
    35773590#endif
    3578                 fStartTimer = true;
     3591                /* Determine the earliest timing slot we need to use. */
     3592                if (tsExpire)
     3593                    tsExpire = RT_MIN(tsExpire, hdaStreamTransferGetNext(pStream));
     3594                else
     3595                    tsExpire = hdaStreamTransferGetNext(pStream);
     3596
     3597                Log2Func(("[SD%RU8] tsExpire=%RU64\n", pStream->u8SD, tsExpire));
    35793598            }
    35803599        }
    35813600    }
    35823601
    3583 #ifndef VBOX_WITH_AUDIO_CALLBACKS
    35843602    /* Start the timer if one of the above streams were active during taking the saved state. */
    3585     if (fStartTimer)
    3586         hdaTimerMaybeStart(pThis);
    3587 #endif
     3603    if (tsExpire)
     3604    {
     3605        LogFunc(("Resuming timer at %RU64\n", tsExpire));
     3606        hdaTimerSet(pThis, tsExpire, true /* fForce */);
     3607    }
    35883608
    35893609    LogFlowFuncLeaveRC(rc);
     
    39733993        }
    39743994
    3975         /*
    3976          * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
    3977          */
    39783995        rc = SSMR3GetStructEx(pSSM, &pStrm->State, sizeof(HDASTREAMSTATE),
    39793996                              0 /* fFlags */, g_aSSMStreamStateFields7,
     
    39813998        AssertRC(rc);
    39823999
     4000        /*
     4001         * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
     4002         */
    39834003        rc = SSMR3GetStructEx(pSSM, &pStrm->State.BDLE.Desc, sizeof(HDABDLEDESC),
    39844004                              0 /* fFlags */, g_aSSMBDLEDescFields7, NULL);
     
    40094029         * Load internal (FIFO) buffer.
    40104030         */
    4011 
    40124031        uint32_t cbCircBufSize = 0;
    40134032        rc = SSMR3GetU32(pSSM, &cbCircBufSize); /* cbCircBuf */
     
    47314750    if (!CFGMR3AreValuesValid(pCfg, "R0Enabled\0"
    47324751                                    "RCEnabled\0"
    4733                                     "TimerHz\0"))
     4752                                    "TimerHz\0"
     4753                                    "PosAdjustEnabled\0"
     4754                                    "PosAdjustFrames\0"))
     4755    {
    47344756        return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
    47354757                                N_ ("Invalid configuration for the Intel HDA device"));
     4758    }
    47364759
    47374760    int rc = CFGMR3QueryBoolDef(pCfg, "RCEnabled", &pThis->fRCEnabled, false);
     
    47434766        return PDMDEV_SET_ERROR(pDevIns, rc,
    47444767                                N_("HDA configuration error: failed to read R0Enabled as boolean"));
    4745 #ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    4746     uint16_t uTimerHz;
    4747     rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, HDA_TIMER_HZ /* Default value, if not set. */);
     4768
     4769    rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &pThis->u16TimerHz, HDA_TIMER_HZ_DEFAULT /* Default value, if not set. */);
    47484770    if (RT_FAILURE(rc))
    47494771        return PDMDEV_SET_ERROR(pDevIns, rc,
    47504772                                N_("HDA configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
    4751 #endif
     4773
     4774     if (pThis->u16TimerHz != HDA_TIMER_HZ_DEFAULT)
     4775         LogRel(("HDA: Using custom device timer rate (%RU16Hz)\n", pThis->u16TimerHz));
     4776
     4777     rc = CFGMR3QueryBoolDef(pCfg, "PosAdjustEnabled", &pThis->fPosAdjustEnabled, true);
     4778     if (RT_FAILURE(rc))
     4779         return PDMDEV_SET_ERROR(pDevIns, rc,
     4780                                N_("HDA configuration error: failed to read position adjustment enabled as boolean"));
     4781
     4782     if (!pThis->fPosAdjustEnabled)
     4783         LogRel(("HDA: Position adjustment is disabled\n"));
     4784
     4785     rc = CFGMR3QueryU16Def(pCfg, "PosAdjustFrames", &pThis->cPosAdjustFrames, HDA_POS_ADJUST_DEFAULT);
     4786     if (RT_FAILURE(rc))
     4787         return PDMDEV_SET_ERROR(pDevIns, rc,
     4788                                 N_("HDA configuration error: failed to read position adjustment frames as unsigned integer"));
     4789
     4790     if (pThis->cPosAdjustFrames)
     4791         LogRel(("HDA: Using custom position adjustment (%RU16 audio frames)\n", pThis->cPosAdjustFrames));
    47524792
    47534793    /*
     
    51745214    }
    51755215
    5176 # ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    51775216    if (RT_SUCCESS(rc))
    51785217    {
     
    51915230        rc = TMR3TimerSetCritSect(pThis->pTimer, &pThis->CritSect);
    51925231        AssertRCReturn(rc, rc);
    5193 
    5194         pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimer) / uTimerHz;
    5195         LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
    5196     }
    5197 # else
    5198     if (RT_SUCCESS(rc))
    5199     {
    5200         PHDADRIVER pDrv;
    5201         RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
    5202         {
    5203             /* Only register primary driver.
    5204              * The device emulation does the output multiplexing then. */
    5205             if (pDrv->fFlags != PDMAUDIODRVFLAGS_PRIMARY)
    5206                 continue;
    5207 
    5208             PDMAUDIOCBRECORD AudioCallbacks[2];
    5209 
    5210             HDACALLBACKCTX Ctx = { pThis, pDrv };
    5211 
    5212             AudioCallbacks[0].enmType     = PDMAUDIOCALLBACKTYPE_INPUT;
    5213             AudioCallbacks[0].pfnCallback = hdaCallbackInput;
    5214             AudioCallbacks[0].pvCtx       = &Ctx;
    5215             AudioCallbacks[0].cbCtx       = sizeof(HDACALLBACKCTX);
    5216 
    5217             AudioCallbacks[1].enmType     = PDMAUDIOCALLBACKTYPE_OUTPUT;
    5218             AudioCallbacks[1].pfnCallback = hdaCallbackOutput;
    5219             AudioCallbacks[1].pvCtx       = &Ctx;
    5220             AudioCallbacks[1].cbCtx       = sizeof(HDACALLBACKCTX);
    5221 
    5222             rc = pDrv->pConnector->pfnRegisterCallbacks(pDrv->pConnector, AudioCallbacks, RT_ELEMENTS(AudioCallbacks));
    5223             if (RT_FAILURE(rc))
    5224                 break;
    5225         }
    5226     }
    5227 # endif
     5232    }
    52285233
    52295234# ifdef VBOX_WITH_STATISTICS
     
    52335238         * Register statistics.
    52345239         */
    5235 #  ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    52365240        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer,            STAMTYPE_PROFILE, "/Devices/HDA/Timer",             STAMUNIT_TICKS_PER_CALL, "Profiling hdaTimer.");
    5237 #  endif
    52385241        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn,               STAMTYPE_PROFILE, "/Devices/HDA/Input",             STAMUNIT_TICKS_PER_CALL, "Profiling input.");
    52395242        PDMDevHlpSTAMRegister(pDevIns, &pThis->StatOut,              STAMTYPE_PROFILE, "/Devices/HDA/Output",            STAMUNIT_TICKS_PER_CALL, "Profiling output.");
  • trunk/src/VBox/Devices/Audio/DevHDA.h

    r69719 r69919  
    154154    /** Number of active (running) SDn streams. */
    155155    uint8_t                            cStreamsActive;
    156 #ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    157156    /** The timer for pumping data thru the attached LUN drivers. */
    158157    PTMTIMERR3                         pTimer;
    159     /** Flag indicating whether the timer is active or not. */
    160     bool                               fTimerActive;
    161     uint8_t                            u8Padding1[7];
    162     /** Timer ticks per Hz. */
    163     uint64_t                           cTimerTicks;
    164     /** The current timer expire time (in timer ticks). */
    165     uint64_t                           tsTimerExpire;
    166 #endif
    167158#ifdef VBOX_WITH_STATISTICS
    168 # ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    169159    STAMPROFILE                        StatTimer;
    170 # endif
    171160    STAMPROFILE                        StatIn;
    172161    STAMPROFILE                        StatOut;
     
    205194    /** Response Interrupt Count (RINTCNT). */
    206195    uint16_t                           u16RespIntCnt;
     196    /** Position adjustment (in audio frames).
     197     *
     198     *  This is not an official feature of the HDA specs, but used by
     199     *  certain OS drivers (e.g. snd_hda_intel) to work around certain
     200     *  quirks by "real" HDA hardware implementations.
     201     *
     202     *  The position adjustment specifies how many audio frames
     203     *  a stream is ahead from its actual reading/writing position when
     204     *  starting a stream.
     205     */
     206    uint16_t                           cPosAdjustFrames;
     207    /** Whether the position adjustment is enabled or not. */
     208    bool                               fPosAdjustEnabled;
     209    uint8_t                            Padding1[3];
    207210    /** Current IRQ level. */
    208211    uint8_t                            u8IRQL;
     212    /** The device timer Hz rate. Defaults to HDA_TIMER_HZ_DEFAULT. */
     213    uint16_t                           u16TimerHz;
    209214    /** Padding for alignment. */
    210     uint8_t                            au8Padding3[5];
     215    uint8_t                            au8Padding3[3];
    211216#ifdef DEBUG
    212217    HDASTATEDBGINFO                    Dbg;
    213218#endif
    214219} HDASTATE, *PHDASTATE;
    215 
    216 #ifdef VBOX_WITH_AUDIO_HDA_CALLBACKS
    217 typedef struct HDACALLBACKCTX
    218 {
    219     PHDASTATE  pThis;
    220     PHDADRIVER pDriver;
    221 } HDACALLBACKCTX, *PHDACALLBACKCTX;
    222 #endif
    223 
    224220#endif /* !DEV_HDA_H */
    225221
  • trunk/src/VBox/Devices/Audio/DevHDACommon.cpp

    r69119 r69919  
    5353#endif
    5454{
    55     HDA_REG(pThis, INTSTS) = hdaGetINTSTS(pThis);
    56 
    57     Log3Func(("IRQL=%RU8\n", pThis->u8IRQL));
     55    uint32_t uIntSts = hdaGetINTSTS(pThis);
     56
     57    HDA_REG(pThis, INTSTS) = uIntSts;
    5858
    5959    /* NB: It is possible to have GIS set even when CIE/SIEn are all zero; the GIS bit does
    6060     * not control the interrupt signal. See Figure 4 on page 54 of the HDA 1.0a spec.
    6161     */
    62 
    63     /* If global interrupt enable (GIE) is set, check if any enabled interrupts are set. */
     62    /* Global Interrupt Enable (GIE) set? */
    6463    if (   (HDA_REG(pThis, INTCTL) & HDA_INTCTL_GIE)
    6564        && (HDA_REG(pThis, INTSTS) & HDA_REG(pThis, INTCTL) & (HDA_INTCTL_CIE | HDA_STRMINT_MASK)))
    6665    {
    67         if (!pThis->u8IRQL)
    68         {
     66        Log3Func(("Asserted (%s)\n", pszSource));
     67
     68        PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 1 /* Assert */);
     69        pThis->u8IRQL = 1;
     70
    6971#ifdef DEBUG
    70             if (!pThis->Dbg.IRQ.tsProcessedLastNs)
    71                 pThis->Dbg.IRQ.tsProcessedLastNs = RTTimeNanoTS();
    72 
    73             const uint64_t tsLastElapsedNs = RTTimeNanoTS() - pThis->Dbg.IRQ.tsProcessedLastNs;
    74 
    75             if (!pThis->Dbg.IRQ.tsAssertedNs)
    76                 pThis->Dbg.IRQ.tsAssertedNs = RTTimeNanoTS();
    77 
    78             const uint64_t tsAssertedElapsedNs = RTTimeNanoTS() - pThis->Dbg.IRQ.tsAssertedNs;
    79 
    80             pThis->Dbg.IRQ.cAsserted++;
    81             pThis->Dbg.IRQ.tsAssertedTotalNs += tsAssertedElapsedNs;
    82 
    83             const uint64_t avgAssertedUs = (pThis->Dbg.IRQ.tsAssertedTotalNs / pThis->Dbg.IRQ.cAsserted) / 1000;
    84 
    85             if (avgAssertedUs > (1000 / HDA_TIMER_HZ) /* ms */ * 1000) /* Exceeds time slot? */
    86                 Log3Func(("Asserted (%s): %zuus elapsed (%zuus on average) -- %zuus alternation delay\n",
    87                           pszSource, tsAssertedElapsedNs / 1000,
    88                           avgAssertedUs,
    89                           (pThis->Dbg.IRQ.tsDeassertedNs - pThis->Dbg.IRQ.tsAssertedNs) / 1000));
    90 #endif
    91             Log3Func(("Asserted (%s): %RU64us between alternation (WALCLK=%RU64)\n",
    92                       pszSource, tsLastElapsedNs / 1000, pThis->u64WalClk));
    93 
    94             PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 1 /* Assert */);
    95             pThis->u8IRQL = 1;
    96 
    97 #ifdef DEBUG
    98             pThis->Dbg.IRQ.tsAssertedNs = RTTimeNanoTS();
    99             pThis->Dbg.IRQ.tsProcessedLastNs = pThis->Dbg.IRQ.tsAssertedNs;
    100 #endif
    101         }
     72        pThis->Dbg.IRQ.tsAssertedNs = RTTimeNanoTS();
     73        pThis->Dbg.IRQ.tsProcessedLastNs = pThis->Dbg.IRQ.tsAssertedNs;
     74#endif
    10275    }
    10376    else
    10477    {
    105         if (pThis->u8IRQL)
    106         {
    107 #ifdef DEBUG
    108             if (!pThis->Dbg.IRQ.tsProcessedLastNs)
    109                 pThis->Dbg.IRQ.tsProcessedLastNs = RTTimeNanoTS();
    110 
    111             const uint64_t tsLastElapsedNs = RTTimeNanoTS() - pThis->Dbg.IRQ.tsProcessedLastNs;
    112 
    113             if (!pThis->Dbg.IRQ.tsDeassertedNs)
    114                 pThis->Dbg.IRQ.tsDeassertedNs = RTTimeNanoTS();
    115 
    116             const uint64_t tsDeassertedElapsedNs = RTTimeNanoTS() - pThis->Dbg.IRQ.tsDeassertedNs;
    117 
    118             pThis->Dbg.IRQ.cDeasserted++;
    119             pThis->Dbg.IRQ.tsDeassertedTotalNs += tsDeassertedElapsedNs;
    120 
    121             const uint64_t avgDeassertedUs = (pThis->Dbg.IRQ.tsDeassertedTotalNs / pThis->Dbg.IRQ.cDeasserted) / 1000;
    122 
    123             if (avgDeassertedUs > (1000 / HDA_TIMER_HZ) /* ms */ * 1000) /* Exceeds time slot? */
    124                 Log3Func(("Deasserted (%s): %zuus elapsed (%zuus on average)\n",
    125                           pszSource, tsDeassertedElapsedNs / 1000, avgDeassertedUs));
    126 
    127             Log3Func(("Deasserted (%s): %RU64us between alternation (WALCLK=%RU64)\n",
    128                       pszSource, tsLastElapsedNs / 1000, pThis->u64WalClk));
    129 #endif
    130             PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 0 /* Deassert */);
    131             pThis->u8IRQL = 0;
    132 
    133 #ifdef DEBUG
    134             pThis->Dbg.IRQ.tsDeassertedNs    = RTTimeNanoTS();
    135             pThis->Dbg.IRQ.tsProcessedLastNs = pThis->Dbg.IRQ.tsDeassertedNs;
    136 #endif
    137         }
     78        Log3Func(("Deasserted (%s)\n", pszSource));
     79
     80        PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, 0 /* Deassert */);
     81        pThis->u8IRQL = 0;
    13882    }
    13983
     
    184128
    185129#ifdef VBOX_STRICT
    186     const uint64_t u64WalClkCur = ASMAtomicReadU64(&pThis->u64WalClk);
    187 #endif
    188           uint64_t u64WalClkSet = u64WalClk;
     130    const uint64_t u64WalClkCur       = ASMAtomicReadU64(&pThis->u64WalClk);
     131#endif
    189132
    190133    /* Only drive the WALCLK register forward if all (active) stream periods have passed
     
    205148            /* Get the maximum value of all periods we need to handle.
    206149             * Not the most elegant solution, but works for now ... */
    207             u64WalClk = RT_MAX(u64WalClkSet, u64FrontAbsWalClk);
     150            u64WalClk = RT_MAX(u64WalClk, u64FrontAbsWalClk);
    208151#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
    209152# error "Implement me!"
    210153#endif
    211             u64WalClk = RT_MAX(u64WalClkSet, u64LineInAbsWalClk);
     154            u64WalClk = RT_MAX(u64WalClk, u64LineInAbsWalClk);
    212155#ifdef VBOX_WITH_HDA_MIC_IN
    213             u64WalClk = RT_MAX(u64WalClkSet, u64MicInAbsWalClk);
     156            u64WalClk = RT_MAX(u64WalClk, u64MicInAbsWalClk);
    214157#endif
    215158
    216159#ifdef VBOX_STRICT
    217             AssertMsg(u64WalClkSet >= u64WalClkCur,
     160            AssertMsg(u64WalClk >= u64WalClkCur,
    218161                      ("Setting WALCLK to a value going backwards does not make any sense (old %RU64 vs. new %RU64)\n",
    219                        u64WalClkCur, u64WalClkSet));
    220             if (u64WalClkSet == u64WalClkCur)     /* Setting a stale value? */
     162                       u64WalClkCur, u64WalClk));
     163            if (u64WalClk == u64WalClkCur)     /* Setting a stale value? */
    221164            {
    222165                if (pThis->u8WalClkStaleCnt++ > 3)
    223166                    AssertMsgFailed(("Setting WALCLK to a stale value (%RU64) too often isn't a good idea really. "
    224                                      "Good luck with stuck audio stuff.\n", u64WalClkSet));
     167                                     "Good luck with stuck audio stuff.\n", u64WalClk));
    225168            }
    226169            else
     
    230173
    231174        /* Set the new WALCLK value. */
    232         ASMAtomicWriteU64(&pThis->u64WalClk, u64WalClkSet);
     175        ASMAtomicWriteU64(&pThis->u64WalClk, u64WalClk);
    233176    }
    234177
     
    298241
    299242/**
    300  * Reads DMA data from a given HDA output stream into its associated FIFO buffer.
     243 * Reads DMA data from a given HDA output stream.
    301244 *
    302245 * @return  IPRT status code.
    303246 * @param   pThis               HDA state.
    304247 * @param   pStream             HDA output stream to read DMA data from.
    305  * @param   cbToRead            How much (in bytes) to read from DMA.
     248 * @param   pvBuf               Where to store the read data.
     249 * @param   cbBuf               How much to read in bytes.
    306250 * @param   pcbRead             Returns read bytes from DMA. Optional.
    307251 */
    308 int hdaDMARead(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)
     252int hdaDMARead(PHDASTATE pThis, PHDASTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
    309253{
    310254    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     
    312256    /* pcbRead is optional. */
    313257
     258    PHDABDLE pBDLE       = &pStream->State.BDLE;
     259
    314260    int rc = VINF_SUCCESS;
    315261
    316262    uint32_t cbReadTotal = 0;
    317 
    318     PHDABDLE   pBDLE     = &pStream->State.BDLE;
    319     PRTCIRCBUF pCircBuf  = pStream->State.pCircBuf;
    320     AssertPtr(pCircBuf);
     263    uint32_t cbLeft      = RT_MIN(cbBuf, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
    321264
    322265#ifdef HDA_DEBUG_SILENCE
     
    327270#endif
    328271
    329     while (cbToRead)
    330     {
    331         /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */
    332         void *pvBuf;
    333         size_t cbBuf;
    334         RTCircBufAcquireWriteBlock(pCircBuf, RT_MIN(cbToRead, pStream->u16FIFOS), &pvBuf, &cbBuf);
    335 
    336         if (cbBuf)
     272    RTGCPHYS addrChunk = pBDLE->Desc.u64BufAdr + pBDLE->State.u32BufOff;
     273
     274    while (cbLeft)
     275    {
     276        uint32_t cbChunk = RT_MIN(cbLeft, pStream->u16FIFOS);
     277
     278        rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), addrChunk, (uint8_t *)pvBuf + cbReadTotal, cbChunk);
     279        if (RT_FAILURE(rc))
     280            break;
     281
     282#ifdef HDA_DEBUG_SILENCE
     283        uint16_t *pu16Buf = (uint16_t *)pvBuf;
     284        for (size_t i = 0; i < cbChunk / sizeof(uint16_t); i++)
    337285        {
    338             /*
    339              * Read from the current BDLE's DMA buffer.
    340              */
    341             int rc2 = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
    342                                         pBDLE->Desc.u64BufAdr + pBDLE->State.u32BufOff + cbReadTotal, pvBuf, cbBuf);
     286            if (*pu16Buf == 0)
     287            {
     288                csSilence++;
     289            }
     290            else
     291                break;
     292            pu16Buf++;
     293        }
     294#endif
     295
     296#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
     297        RTFILE fh;
     298        int rc2 = RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaDMARead.pcm",
     299                             RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
     300        if (RT_SUCCESS(rc2))
     301        {
     302            RTFileWrite(fh, (uint8_t *)pvBuf + cbReadTotal, cbChunk, NULL);
     303            RTFileClose(fh);
     304        }
     305        else
    343306            AssertRC(rc2);
    344 
    345 #ifdef HDA_DEBUG_SILENCE
    346             uint16_t *pu16Buf = (uint16_t *)pvBuf;
    347             for (size_t i = 0; i < cbBuf / sizeof(uint16_t); i++)
    348             {
    349                 if (*pu16Buf == 0)
    350                 {
    351                     csSilence++;
    352                 }
    353                 else
    354                     break;
    355                 pu16Buf++;
    356             }
    357 #endif
    358 
    359 #ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
    360             if (cbBuf)
    361             {
    362                 RTFILE fh;
    363                 rc2 = RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaDMARead.pcm",
    364                                  RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
    365                 if (RT_SUCCESS(rc2))
    366                 {
    367                     RTFileWrite(fh, pvBuf, cbBuf, NULL);
    368                     RTFileClose(fh);
    369                 }
    370                 else
    371                     AssertRC(rc2);
    372             }
    373 #endif
    374 
    375 #if 0
    376             pStream->Dbg.cbReadTotal += cbBuf;
    377             const uint64_t cbWritten = ASMAtomicReadU64(&pStream->Dbg.cbWrittenTotal);
    378             Log3Func(("cbRead=%RU64, cbWritten=%RU64 -> %RU64 bytes %s\n",
    379                       pStream->Dbg.cbReadTotal, cbWritten,
    380                       pStream->Dbg.cbReadTotal >= cbWritten ? pStream->Dbg.cbReadTotal - cbWritten : cbWritten - pStream->Dbg.cbReadTotal,
    381                       pStream->Dbg.cbReadTotal > cbWritten ? "too much" : "too little"));
    382307#endif
    383308
    384309#ifdef VBOX_WITH_STATISTICS
    385             STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBuf);
    386 #endif
    387         }
    388 
    389         RTCircBufReleaseWriteBlock(pCircBuf, cbBuf);
    390 
    391         if (!cbBuf)
    392         {
    393             rc = VERR_BUFFER_OVERFLOW;
    394             break;
    395         }
    396 
    397         cbReadTotal += (uint32_t)cbBuf;
    398         Assert(pBDLE->State.u32BufOff + cbReadTotal <= pBDLE->Desc.u32BufSize);
    399 
    400         Assert(cbToRead >= cbBuf);
    401         cbToRead    -= (uint32_t)cbBuf;
     310        STAM_COUNTER_ADD(&pThis->StatBytesRead, cbChunk);
     311#endif
     312        addrChunk         = (addrChunk + cbChunk) % pBDLE->Desc.u32BufSize;
     313
     314        Assert(cbLeft    >= cbChunk);
     315        cbLeft           -= cbChunk;
     316
     317        cbReadTotal      += cbChunk;
    402318    }
    403319
     
    431347 * @param   pThis               HDA state.
    432348 * @param   pStream             HDA input stream to write audio data to.
    433  * @param   cbToWrite           How much (in bytes) to write.
     349 * @param   pvBuf               Data to write.
     350 * @param   cbBuf               How much (in bytes) to write.
    434351 * @param   pcbWritten          Returns written bytes on success. Optional.
    435352 */
    436 int hdaDMAWrite(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
     353int hdaDMAWrite(PHDASTATE pThis, PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
    437354{
    438355    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     
    440357    /* pcbWritten is optional. */
    441358
    442     PHDABDLE   pBDLE    = &pStream->State.BDLE;
    443     PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
    444     AssertPtr(pCircBuf);
     359    PHDABDLE pBDLE  = &pStream->State.BDLE;
    445360
    446361    int rc = VINF_SUCCESS;
    447362
    448363    uint32_t cbWrittenTotal = 0;
    449 
    450     void *pvBuf  = NULL;
    451     size_t cbBuf = 0;
    452 
    453     uint8_t abSilence[HDA_FIFO_MAX + 1] = { 0 };
    454 
    455     while (cbToWrite)
    456     {
    457         size_t cbChunk = RT_MIN(cbToWrite, pStream->u16FIFOS);
    458 
    459         size_t cbBlock = 0;
    460         RTCircBufAcquireReadBlock(pCircBuf, cbChunk, &pvBuf, &cbBlock);
    461 
    462         if (cbBlock)
    463         {
    464             cbBuf = cbBlock;
    465         }
    466         else /* No audio data available? Send silence. */
    467         {
    468             pvBuf = &abSilence;
    469             cbBuf = cbChunk;
    470         }
     364    uint32_t cbLeft = RT_MIN(cbBuf, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
     365
     366    RTGCPHYS addrChunk = pBDLE->Desc.u64BufAdr + pBDLE->State.u32BufOff;
     367
     368    while (cbLeft)
     369    {
     370        uint32_t cbChunk = RT_MIN(cbLeft, pStream->u16FIFOS);
    471371
    472372        /* Sanity checks. */
    473         Assert(cbBuf <= pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
    474         Assert(cbBuf % HDA_FRAME_SIZE == 0);
    475         Assert((cbBuf >> 1) >= 1);
     373        Assert(cbChunk <= pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
     374        Assert(cbChunk % HDA_FRAME_SIZE == 0);
     375        Assert((cbChunk >> 1) >= 1);
    476376
    477377#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
     
    479379        RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaDMAWrite.pcm",
    480380                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
    481         RTFileWrite(fh, pvBuf, cbBuf, NULL);
     381        RTFileWrite(fh, pvBuf, cbChunk, NULL);
    482382        RTFileClose(fh);
    483383#endif
    484         int rc2 = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
    485                                         pBDLE->Desc.u64BufAdr + pBDLE->State.u32BufOff + cbWrittenTotal,
    486                                         pvBuf, cbBuf);
    487         AssertRC(rc2);
     384        rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
     385                                   addrChunk, (uint8_t *)pvBuf + cbWrittenTotal, cbChunk);
     386        if (RT_FAILURE(rc))
     387            break;
    488388
    489389#ifdef VBOX_WITH_STATISTICS
    490         STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbBuf);
    491 #endif
    492         if (cbBlock)
    493             RTCircBufReleaseReadBlock(pCircBuf, cbBlock);
    494 
    495         Assert(cbToWrite >= cbBuf);
    496         cbToWrite -= (uint32_t)cbBuf;
    497 
    498         cbWrittenTotal += (uint32_t)cbBuf;
     390        STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbChunk);
     391#endif
     392        addrChunk       = (addrChunk + cbChunk) % pBDLE->Desc.u32BufSize;
     393
     394        Assert(cbLeft  >= cbChunk);
     395        cbLeft -= (uint32_t)cbChunk;
     396
     397        cbWrittenTotal += (uint32_t)cbChunk;
    499398    }
    500399
     
    707606    return (pBDLE->Desc.fFlags & HDA_BDLE_FLAG_IOC);
    708607}
     608
     609/**
     610 * Sets the virtual device timer to a new expiration time.
     611 *
     612 * @returns Whether the new expiration time was set or not.
     613 * @param   pThis               HDA state.
     614 * @param   tsExpire            New (virtual) expiration time to set.
     615 * @param   fForce              Whether to force setting the expiration time or not.
     616 *
     617 * @remark  This function takes all active HDA streams and their
     618 *          current timing into account. This is needed to make sure
     619 *          that all streams can match their needed timing.
     620 *
     621 *          To achieve this, the earliest (lowest) timestamp of all
     622 *          active streams found will be used for the next scheduling slot.
     623 *
     624 *          Forcing a new expiration time will override the above mechanism.
     625 */
     626bool hdaTimerSet(PHDASTATE pThis, uint64_t tsExpire, bool fForce)
     627{
     628    AssertPtr(pThis->pTimer);
     629
     630    uint64_t tsExpireMin = tsExpire;
     631
     632    if (!fForce)
     633    {
     634        for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
     635        {
     636            PHDASTREAM pStream = &pThis->aStreams[i];
     637
     638            if (!(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_SDCTL_RUN))
     639                continue;
     640
     641            if (hdaStreamTransferIsScheduled(pStream))
     642                tsExpireMin = RT_MIN(tsExpireMin, hdaStreamTransferGetNext(pStream));
     643        }
     644    }
     645
     646    const uint64_t tsNow = TMTimerGet(pThis->pTimer);
     647
     648    if (tsExpireMin < tsNow) /* Make sure to not go backwards in time. */
     649        tsExpireMin = tsNow;
     650
     651    Log3Func(("u64Epxire=%RU64 -> u64ExpireMin=%RU64, fForce=%RTbool [%s]\n",
     652              tsExpire, tsExpireMin, fForce, tsExpireMin == tsExpire ? "OK" : "DELAYED"));
     653
     654    int rc2 = TMTimerSet(pThis->pTimer, tsExpireMin);
     655    AssertRC(rc2);
     656
     657    return tsExpireMin == tsExpire;
     658}
    709659#endif /* IN_RING3 */
    710660
  • trunk/src/VBox/Devices/Audio/DevHDACommon.h

    r69719 r69919  
    8989/** Default timer frequency (in Hz).
    9090 *
    91  *  Note: Keep in mind that the Hz rate has nothing to do with samples rates
    92  *        or DMA / interrupt timing -- it's purely needed in order to drive
    93  *        the data flow at a constant (and sufficient) rate.
    94  *
    95  *        Lowering this value can ask for trouble, as backends then can run
    96  *        into data underruns. */
    97 #define HDA_TIMER_HZ                200
     91 * Lowering this value can ask for trouble, as backends then can run
     92 * into data underruns. */
     93#define HDA_TIMER_HZ_DEFAULT        100
     94
     95/** Default position adjustment (in audio samples).
     96 *
     97 * For snd_hda_intel (Linux guests), the first BDL entry always is being used as
     98 * so-called BDL adjustment, which can vary, and is being used for chipsets which
     99 * misbehave and/or are incorrectly implemented.
     100 *
     101 * The BDL adjustment entry *always* has the IOC (Interrupt on Completion) bit set.
     102 *
     103 * For Intel Baytrail / Braswell implementations the BDL default adjustment is 32 frames, whereas
     104 * for ICH / PCH it's only one (1) frame.
     105 *
     106 * See default_bdl_pos_adj() and snd_hdac_stream_setup_periods() for more information.
     107 *
     108 * By default we apply some simple heuristics in hdaStreamInit().
     109 */
     110#define HDA_POS_ADJUST_DEFAULT      0
    98111
    99112/** HDA's (fixed) audio frame size in bytes.
     
    231244#define HDA_REG_CORBSIZE            21          /* 0x4E */
    232245#define HDA_RMX_CORBSIZE            19
     246#define HDA_CORBSIZE_SZ_CAP         0xF0
     247#define HDA_CORBSIZE_SZ             0x3
    233248
    234249/** Number of CORB buffer entries. */
    235250#define HDA_CORB_SIZE               256
     251/** CORB element size (in bytes). */
     252#define HDA_CORB_ELEMENT_SIZE       4
    236253/** Number of RIRB buffer entries. */
    237254#define HDA_RIRB_SIZE               256
     255/** RIRB element size (in bytes). */
     256#define HDA_RIRB_ELEMENT_SIZE       8
    238257
    239258#define HDA_REG_RIRBLBASE           22          /* 0x50 */
     
    586605 * @{
    587606 */
    588 int           hdaDMARead(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead);
    589 int           hdaDMAWrite(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten);
     607int           hdaDMARead(PHDASTATE pThis, PHDASTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
     608int           hdaDMAWrite(PHDASTATE pThis, PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
    590609/** @} */
    591610
     
    609628/** @} */
    610629
     630/** @name Device timer functions.
     631 * @{
     632 */
     633#ifdef IN_RING3
     634bool          hdaTimerSet(PHDASTATE pThis, uint64_t u64Expire, bool fForce);
     635#endif /* IN_RING3 */
     636/** @} */
     637
    611638#endif /* !DEV_HDA_H_COMMON */
    612639
  • trunk/src/VBox/Devices/Audio/HDAStream.cpp

    r69119 r69919  
    9292    rc2 = hdaStreamAsyncIODestroy(pStream);
    9393    AssertRC(rc2);
    94 #else
    95     RT_NOREF(pThis);
    9694#endif
    9795
     
    137135
    138136    /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */
    139     hdaStreamUpdateLPIB(pStream, HDA_STREAM_REG(pThis, LPIB, pStream->u8SD));
     137    hdaStreamSetPosition(pStream, HDA_STREAM_REG(pThis, LPIB, pStream->u8SD));
    140138
    141139    PPDMAUDIOSTREAMCFG pCfg = &pStream->State.Cfg;
     
    187185    LogFunc(("[SD%RU8] DMA @ 0x%x (%RU32 bytes), LVI=%RU16, FIFOS=%RU16, rc=%Rrc\n",
    188186             pStream->u8SD, pStream->u64BDLBase, pStream->u32CBL, pStream->u16LVI, pStream->u16FIFOS, rc));
     187
     188    if (   pStream->u32CBL
     189        && pStream->u16LVI)
     190    {
     191        /* Make sure that the chosen Hz rate dividable by the stream's rate. */
     192        if (pStream->State.Cfg.Props.uHz % pThis->u16TimerHz != 0)
     193            LogRel(("HDA: Device timer (%RU32) does not fit to stream #RU8 timing (%RU32)\n",
     194                    pThis->u16TimerHz, pStream->State.Cfg.Props.uHz));
     195
     196        /** @todo Use a more dynamic fragment size? */
     197        uint8_t cFragments = pStream->u16LVI;
     198        if (cFragments <= 1)
     199            cFragments = 2; /* At least two fragments (BDLEs) must be present. */
     200
     201        /* Calculate the fragment size the guest OS expects interrupt delivery at. */
     202        pStream->State.cbTransferSize = pStream->u32CBL / cFragments;
     203        Assert(pStream->State.cbTransferSize);
     204        Assert(pStream->State.cbTransferSize % HDA_FRAME_SIZE == 0);
     205
     206        /* Calculate the bytes we need to transfer to / from the stream's DMA per iteration.
     207         * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. */
     208        pStream->State.cbTransferChunk = (pStream->State.Cfg.Props.uHz / pThis->u16TimerHz) * HDA_FRAME_SIZE;
     209        Assert(pStream->State.cbTransferChunk);
     210        Assert(pStream->State.cbTransferChunk % HDA_FRAME_SIZE == 0);
     211
     212        /* Make sure that the transfer chunk does not exceed the overall transfer size. */
     213        if (pStream->State.cbTransferChunk > pStream->State.cbTransferSize)
     214            pStream->State.cbTransferChunk = pStream->State.cbTransferSize;
     215
     216        pStream->State.cbTransferProcessed        = 0;
     217        pStream->State.cTransferPendingInterrupts = 0;
     218
     219        const uint64_t cTicksPerHz = TMTimerGetFreq(pThis->pTimer) / pThis->u16TimerHz;
     220
     221        /* Calculate the timer ticks per byte for this stream. */
     222        pStream->State.cTicksPerByte = cTicksPerHz / pStream->State.cbTransferChunk;
     223        Assert(pStream->State.cTicksPerByte);
     224
     225        /* Calculate timer ticks per transfer. */
     226        pStream->State.cTransferTicks     = pStream->State.cbTransferChunk * pStream->State.cTicksPerByte;
     227
     228        /* Initialize the transfer timestamps. */
     229        pStream->State.tsTransferLast     = 0;
     230        pStream->State.tsTransferNext     = 0;
     231
     232        LogFunc(("[SD%RU8] Timer %uHz (%RU64 ticks per Hz), ticks per byte: %RU64 (%RU64 bytes per iteration = %RU64 ticks)," \
     233                 " transfer size = %RU64\n",
     234                 pStream->u8SD, pThis->u16TimerHz, cTicksPerHz, pStream->State.cTicksPerByte,
     235                 pStream->State.cbTransferChunk, pStream->State.cTransferTicks, pStream->State.cbTransferSize));
     236        /*
     237         * Handle the stream's position adjustment.
     238         */
     239        uint32_t cfPosAdjust = 0;
     240
     241        if (pThis->fPosAdjustEnabled) /* Is the position adjustment enabled at all? */
     242        {
     243            /* If no custom set position adjustment is set, apply some
     244             * simple heuristics to detect the appropriate position adjustment. */
     245            if (   pStream->u64BDLBase
     246                && !pThis->cPosAdjustFrames)
     247            {
     248                HDABDLE BDLE;
     249                int rc2 = hdaBDLEFetch(pThis, &BDLE, pStream->u64BDLBase, 0 /* Entry */);
     250                AssertRC(rc2);
     251
     252                /** @todo Implement / use a (dynamic) table once this gets more complicated. */
     253
     254#ifdef VBOX_WITH_INTEL_HDA
     255                /* Intel ICH / PCH: 1 frame. */
     256                if (BDLE.Desc.u32BufSize == 1 * HDA_FRAME_SIZE)
     257                {
     258                    cfPosAdjust = 1;
     259                }
     260                /* Intel Baytrail / Braswell: 32 frames. */
     261                else if (BDLE.Desc.u32BufSize == 32 * HDA_FRAME_SIZE)
     262                {
     263                    cfPosAdjust = 32;
     264                }
     265                else
     266#endif
     267                    cfPosAdjust = pThis->cPosAdjustFrames;
     268            }
     269            else /* Go with the set default. */
     270                cfPosAdjust = pThis->cPosAdjustFrames;
     271
     272            if (cfPosAdjust)
     273            {
     274                /* Initialize position adjustment counter. */
     275                pStream->State.cPosAdjustFramesLeft = cfPosAdjust;
     276                LogRel2(("HDA: Position adjustment for stream #%RU8 active (%RU32 frames)\n", pStream->u8SD, cfPosAdjust));
     277            }
     278        }
     279
     280        LogFunc(("[SD%RU8] cfPosAdjust=%RU32\n", pStream->u8SD, cfPosAdjust));
     281    }
    189282
    190283    return rc;
     
    239332#endif
    240333
     334    pStream->State.tsTransferLast = 0;
     335    pStream->State.tsTransferNext = 0;
     336
    241337    RT_ZERO(pStream->State.BDLE);
    242338    pStream->State.uCurBDLE = 0;
     
    304400}
    305401
    306 /**
    307  * Returns the number of outstanding stream data bytes which need to be processed
    308  * by the DMA engine assigned to this stream.
    309  *
    310  * @return Number of bytes for the DMA engine to process.
    311  */
    312 uint32_t hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStream)
    313 {
    314     AssertPtrReturn(pThis, 0);
    315     AssertPtrReturn(pStream, 0);
    316 
    317     if (!RT_BOOL(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_SDCTL_RUN))
    318     {
    319         AssertFailed(); /* Should never happen. */
    320         return 0;
    321     }
    322 
    323     /* Determine how much for the current BDL entry we have left to transfer. */
    324     PHDABDLE pBDLE  = &pStream->State.BDLE;
    325     const uint32_t cbBDLE = RT_MIN(pBDLE->Desc.u32BufSize, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
    326 
    327     /* Determine how much we (still) can stuff in the stream's internal FIFO.  */
    328     const uint32_t cbCircBuf   = (uint32_t)RTCircBufFree(pStream->State.pCircBuf);
    329 
    330     uint32_t cbToTransfer = cbBDLE;
    331 
    332     /* Make sure that we don't transfer more than our FIFO can hold at the moment.
    333      * As the host sets the overall pace it needs to process some of the FIFO data first before
    334      * we can issue a new DMA data transfer. */
    335     if (cbToTransfer > cbCircBuf)
    336         cbToTransfer = cbCircBuf;
    337 
    338     Log3Func(("[SD%RU8] LPIB=%RU32 CBL=%RU32 cbCircBuf=%RU32, -> cbToTransfer=%RU32 %R[bdle]\n", pStream->u8SD,
    339               HDA_STREAM_REG(pThis, LPIB, pStream->u8SD), pStream->u32CBL, cbCircBuf, cbToTransfer, pBDLE));
    340     return cbToTransfer;
    341 }
    342 
    343 /**
    344  * Increases the amount of transferred (audio) data of an HDA stream and
    345  * reports this as needed to the guest.
    346  *
    347  * @param  pStream              HDA stream to increase amount for.
    348  * @param  cbInc                Amount (in bytes) to increase.
    349  */
    350 void hdaStreamTransferInc(PHDASTREAM pStream, uint32_t cbInc)
     402uint32_t hdaStreamGetPosition(PHDASTATE pThis, PHDASTREAM pStream)
     403{
     404    return HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
     405}
     406
     407/**
     408 * Updates an HDA stream's current read or write buffer position (depending on the stream type) by
     409 * updating its associated LPIB register and DMA position buffer (if enabled).
     410 *
     411 * @param   pThis               HDA state.
     412 * @param   pStream             HDA stream to update read / write position for.
     413 * @param   u32LPIB             Absolute position (in bytes) to set current read / write position to.
     414 */
     415void hdaStreamSetPosition(PHDASTREAM pStream, uint32_t u32LPIB)
    351416{
    352417    AssertPtrReturnVoid(pStream);
    353418
    354     if (!cbInc)
    355         return;
    356 
    357     const PHDASTATE pThis  = pStream->pHDAState;
    358 
    359     const uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
    360 
    361     Log3Func(("[SD%RU8] %RU32 + %RU32 -> %RU32, CBL=%RU32\n",
    362               pStream->u8SD, u32LPIB, cbInc, u32LPIB + cbInc, pStream->u32CBL));
    363 
    364     hdaStreamUpdateLPIB(pStream, u32LPIB + cbInc);
     419    Assert(u32LPIB % HDA_FRAME_SIZE == 0);
     420
     421    Log3Func(("[SD%RU8] LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",
     422              pStream->u8SD, u32LPIB, pStream->pHDAState->fDMAPosition));
     423
     424    /* Update LPIB in any case. */
     425    HDA_STREAM_REG(pStream->pHDAState, LPIB, pStream->u8SD) = u32LPIB;
     426
     427    /* Do we need to tell the current DMA position? */
     428    if (pStream->pHDAState->fDMAPosition)
     429    {
     430        int rc2 = PDMDevHlpPCIPhysWrite(pStream->pHDAState->CTX_SUFF(pDevIns),
     431                                        pStream->pHDAState->u64DPBase + (pStream->u8SD * 2 * sizeof(uint32_t)),
     432                                        (void *)&u32LPIB, sizeof(uint32_t));
     433        AssertRC(rc2);
     434    }
    365435}
    366436
     
    397467}
    398468
     469/**
     470 * Returns whether a next transfer for a given stream is scheduled or not.
     471 *
     472 * @returns True if a next transfer is scheduled, false if not.
     473 * @param   pStream             HDA stream to retrieve schedule status for.
     474 */
     475bool hdaStreamTransferIsScheduled(PHDASTREAM pStream)
     476{
     477    AssertPtrReturn(pStream,            false);
     478    AssertPtrReturn(pStream->pHDAState, false);
     479
     480    const bool fScheduled = pStream->State.tsTransferNext > TMTimerGet(pStream->pHDAState->pTimer);
     481
     482    Log3Func(("[SD%RU8] %RU64 -> %RTbool\n", pStream->u8SD, pStream->State.tsTransferNext, fScheduled));
     483
     484    return fScheduled;
     485}
     486
     487/**
     488 * Returns the (virtual) clock timestamp of the next transfer, if any.
     489 * Will return 0 if no new transfer is scheduled.
     490 *
     491 * @returns The (virtual) clock timestamp of the next transfer.
     492 * @param   pStream             HDA stream to retrieve timestamp for.
     493 */
     494uint64_t hdaStreamTransferGetNext(PHDASTREAM pStream)
     495{
     496    return pStream->State.tsTransferNext;
     497}
    399498
    400499/**
     
    403502 * @returns IPRT status code.
    404503 * @param   pStream             HDA stream to write to.
    405  * @param   cbToWrite           Number of bytes to write.
     504 * @param   pvBuf               Data buffer to write.
     505 *                              If NULL, silence will be written.
     506 * @param   cbBuf               Number of bytes of data buffer to write.
    406507 * @param   pcbWritten          Number of bytes written. Optional.
    407508 */
    408 int hdaStreamWrite(PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
     509int hdaStreamWrite(PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
    409510{
    410511    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    411     AssertReturn(cbToWrite,  VERR_INVALID_PARAMETER);
     512    /* pvBuf is optional. */
     513    AssertReturn(cbBuf,      VERR_INVALID_PARAMETER);
    412514    /* pcbWritten is optional. */
    413 
    414     PHDAMIXERSINK pSink = pStream->pMixSink;
    415     if (!pSink)
    416     {
    417         AssertMsgFailed(("[SD%RU8]: Can't write to a stream with no sink attached\n", pStream->u8SD));
    418 
    419         if (pcbWritten)
    420             *pcbWritten = 0;
    421         return VINF_SUCCESS;
    422     }
    423515
    424516    PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
     
    428520
    429521    uint32_t cbWrittenTotal = 0;
    430     uint32_t cbLeft         = RT_MIN(cbToWrite, (uint32_t)RTCircBufFree(pCircBuf));
     522    uint32_t cbLeft         = RT_MIN(cbBuf, (uint32_t)RTCircBufFree(pCircBuf));
    431523
    432524    while (cbLeft)
     
    435527        size_t cbDst;
    436528
    437         uint32_t cbRead = 0;
    438 
    439529        RTCircBufAcquireWriteBlock(pCircBuf, cbLeft, &pvDst, &cbDst);
    440530
    441531        if (cbDst)
    442532        {
    443             rc = AudioMixerSinkRead(pSink->pMixSink, AUDMIXOP_COPY, pvDst, (uint32_t)cbDst, &cbRead);
    444             AssertRC(rc);
    445 
    446             Assert(cbDst >= cbRead);
    447             Log2Func(("[SD%RU8]: %RU32/%zu bytes read\n", pStream->u8SD, cbRead, cbDst));
     533            if (pvBuf)
     534            {
     535                memcpy(pvDst, (uint8_t *)pvBuf + cbWrittenTotal, cbDst);
     536            }
     537            else /* Send silence. */
     538            {
     539                /** @todo Use a sample spec for "silence" based on the PCM parameters.
     540                 *        For now we ASSUME that silence equals NULLing the data. */
     541                RT_BZERO(pvDst, cbDst);
     542            }
    448543
    449544#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
     
    451546            RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaStreamWrite.pcm",
    452547                       RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
    453             RTFileWrite(fh, pvDst, cbRead, NULL);
     548            RTFileWrite(fh, pvDst, cbDst, NULL);
    454549            RTFileClose(fh);
    455550#endif
    456551        }
    457552
    458         RTCircBufReleaseWriteBlock(pCircBuf, cbRead);
     553        RTCircBufReleaseWriteBlock(pCircBuf, cbDst);
    459554
    460555        if (RT_FAILURE(rc))
    461556            break;
    462557
    463         Assert(cbLeft  >= cbRead);
    464         cbLeft         -= cbRead;
    465 
    466         cbWrittenTotal += cbRead;
     558        Assert(cbLeft  >= cbDst);
     559        cbLeft         -= cbDst;
     560
     561        cbWrittenTotal += cbDst;
    467562    }
    468563
     
    548643}
    549644
    550 uint32_t hdaStreamTransferGetElapsed(PHDASTREAM pStream)
    551 {
    552     AssertPtr(pStream->pHDAState->pTimer);
    553     const uint64_t cTicksNow     = TMTimerGet(pStream->pHDAState->pTimer);
    554     const uint64_t cTicksPerSec  = TMTimerGetFreq(pStream->pHDAState->pTimer);
    555 
    556     const uint64_t cTicksElapsed = cTicksNow - pStream->State.uTimerTS;
    557 #ifdef DEBUG
    558     const uint64_t cMsElapsed    = cTicksElapsed / (cTicksPerSec / 1000);
    559 #endif
    560 
    561     AssertPtr(pStream->pHDAState->pCodec);
    562 
    563     PPDMAUDIOSTREAMCFG pCfg = &pStream->State.Cfg;
    564 
    565     /* A stream *always* runs with 48 kHz device-wise, regardless of the actual stream input/output format (Hz) being set. */
    566     uint32_t csPerPeriod = (int)((pCfg->Props.cChannels * cTicksElapsed * 48000 /* Hz */ + cTicksPerSec) / cTicksPerSec / 2);
    567     uint32_t cbPerPeriod = csPerPeriod << pCfg->Props.cShift;
    568 
    569     Log3Func(("[SD%RU8] %RU64ms (%zu samples, %zu bytes) elapsed\n", pStream->u8SD, cMsElapsed, csPerPeriod, cbPerPeriod));
    570 
    571     return cbPerPeriod;
    572 }
    573 
    574645/**
    575646 * Transfers data of an HDA stream according to its usage (input / output).
     
    583654 * @returns IPRT status code.
    584655 * @param   pStream             HDA stream to update.
    585  * @param   cbToProcessMax      Maximum of data (in bytes) to process.
    586656 */
    587657int hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax)
    588658{
    589     AssertPtrReturn(pStream,        VERR_INVALID_POINTER);
    590     AssertReturn(cbToProcessMax,    VERR_INVALID_PARAMETER);
     659    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
    591660
    592661    hdaStreamLock(pStream);
     
    607676        fProceed = false;
    608677    }
    609     /* Period complete? */
    610     else if (hdaStreamPeriodIsComplete(pPeriod))
    611     {
    612         Log3Func(("[SD%RU8] Period is complete, nothing to do\n", pStream->u8SD));
     678    else if (HDA_STREAM_REG(pThis, STS, pStream->u8SD) & HDA_SDSTS_BCIS)
     679    {
     680        Log3Func(("[SD%RU8] BCIS bit set\n", pStream->u8SD));
    613681        fProceed = false;
    614682    }
     
    620688        return VINF_SUCCESS;
    621689    }
     690
     691    const uint64_t tsNow = TMTimerGet(pThis->pTimer);
     692
     693    if (!pStream->State.tsTransferLast)
     694        pStream->State.tsTransferLast = tsNow;
     695
     696#ifdef DEBUG
     697    const int64_t iTimerDelta = tsNow - pStream->State.tsTransferLast;
     698    Log3Func(("[SD%RU8] Time now=%RU64, last=%RU64 -> %RI64 ticks delta\n",
     699              pStream->u8SD, tsNow, pStream->State.tsTransferLast, iTimerDelta));
     700#endif
     701
     702    pStream->State.tsTransferLast = tsNow;
    622703
    623704    /* Sanity checks. */
     
    625706    Assert(pStream->u64BDLBase);
    626707    Assert(pStream->u32CBL);
     708    Assert(pStream->u16FIFOS);
    627709
    628710    /* State sanity checks. */
     
    637719    }
    638720
    639     const uint32_t cbPeriodRemaining = hdaStreamPeriodGetRemainingFrames(pPeriod) * HDA_FRAME_SIZE;
    640     Assert(cbPeriodRemaining); /* Paranoia. */
    641 
    642     const uint32_t cbElapsed         = hdaStreamTransferGetElapsed(pStream);
    643     Assert(cbElapsed);         /* Paranoia. */
    644 
    645     /* Limit the data to read, as this routine could be delayed and therefore
    646      * report wrong (e.g. too much) cbElapsed bytes. */
    647     uint32_t cbLeft                  = RT_MIN(RT_MIN(cbPeriodRemaining, cbElapsed), cbToProcessMax);
    648 
    649     Log3Func(("[SD%RU8] cbPeriodRemaining=%RU32, cbElapsed=%RU32, cbToProcessMax=%RU32 -> cbLeft=%RU32\n",
    650               pStream->u8SD, cbPeriodRemaining, cbElapsed, cbToProcessMax, cbLeft));
    651 
    652     Assert(cbLeft % HDA_FRAME_SIZE == 0); /* Paranoia. */
    653 
     721    uint32_t cbToProcess = RT_MIN(pStream->State.cbTransferSize - pStream->State.cbTransferProcessed,
     722                                  pStream->State.cbTransferChunk);
     723    uint32_t cbProcessed = 0;
     724    uint32_t cbLeft      = cbToProcess;
     725    Assert(cbLeft % HDA_FRAME_SIZE == 0);
     726
     727    if (cbToProcess > cbToProcessMax)
     728        LogRel2(("HDA: More data to process\n"));
     729
     730    Log3Func(("[SD%RU8] cbToProcess=%RU32\n", pStream->u8SD, cbToProcess));
     731
     732    uint8_t abChunk[HDA_FIFO_MAX + 1];
    654733    while (cbLeft)
    655734    {
    656         uint32_t cbChunk = RT_MIN(hdaStreamGetTransferSize(pThis, pStream), cbLeft);
     735        /* Limit the chunk to the stream's FIFO size and what's left to process. */
     736        uint32_t cbChunk = RT_MIN(cbLeft, pStream->u16FIFOS);
     737
     738        /* Limit the chunk to the remaining data of the current BDLE. */
     739        cbChunk = RT_MIN(cbChunk, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);
     740
     741        /* If there are position adjustment frames left to be processed,
     742         * make sure that we process them first as a whole. */
     743        if (pStream->State.cPosAdjustFramesLeft)
     744            cbChunk = RT_MIN(cbChunk, pStream->State.cPosAdjustFramesLeft * HDA_FRAME_SIZE);
     745
     746        Log3Func(("[SD%RU8] cbChunk=%RU32, cPosAdjustFramesLeft=%RU16\n",
     747                  pStream->u8SD, cbChunk, pStream->State.cPosAdjustFramesLeft));
     748
    657749        if (!cbChunk)
    658750            break;
    659751
    660         uint32_t cbDMA   = 0;
    661 
    662         if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */
     752        uint32_t   cbDMA    = 0;
     753        PRTCIRCBUF pCircBuf = pStream->State.pCircBuf;
     754
     755        if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN) /* Input (SDI). */
     756        {
     757            STAM_PROFILE_START(&pThis->StatIn, a);
     758
     759            uint32_t cbDMAWritten = 0;
     760            uint32_t cbDMAToWrite = cbChunk;
     761
     762            while (cbDMAToWrite)
     763            {
     764                void *pvBuf; size_t cbBuf;
     765                RTCircBufAcquireReadBlock(pCircBuf, cbDMAToWrite, &pvBuf, &cbBuf);
     766
     767                if (   !cbBuf
     768                    && !RTCircBufUsed(pCircBuf))
     769                    break;
     770
     771                memcpy(abChunk + cbDMAWritten, pvBuf, cbBuf);
     772
     773                RTCircBufReleaseReadBlock(pCircBuf, cbBuf);
     774
     775                Assert(cbDMAToWrite >= cbBuf);
     776                cbDMAToWrite -= (uint32_t)cbBuf;
     777                cbDMAWritten += (uint32_t)cbBuf;
     778                Assert(cbDMAWritten <= cbChunk);
     779            }
     780
     781            if (cbDMAToWrite)
     782            {
     783                LogRel2(("HDA: FIFO underflow for stream #%RU8 (%RU32 bytes outstanding)\n", pStream->u8SD, cbDMAToWrite));
     784
     785                Assert(cbChunk == cbDMAWritten + cbDMAToWrite);
     786                memset((uint8_t *)abChunk + cbDMAWritten, 0, cbDMAToWrite);
     787                cbDMAWritten = cbChunk;
     788            }
     789
     790            rc = hdaDMAWrite(pThis, pStream, abChunk, cbDMAWritten, &cbDMA /* pcbWritten */);
     791            if (RT_FAILURE(rc))
     792                LogRel(("HDA: Writing to stream #%RU8 DMA failed with %Rrc\n", pStream->u8SD, rc));
     793
     794            STAM_PROFILE_STOP(&pThis->StatIn, a);
     795        }
     796        else if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */
    663797        {
    664798            STAM_PROFILE_START(&pThis->StatOut, a);
    665799
    666             rc = hdaDMARead(pThis, pStream, cbChunk, &cbDMA /* pcbRead */);
    667             if (RT_FAILURE(rc))
     800            rc = hdaDMARead(pThis, pStream, abChunk, cbChunk, &cbDMA /* pcbRead */);
     801            if (RT_SUCCESS(rc))
     802            {
     803                uint32_t cbDMAWritten = 0;
     804                uint32_t cbDMALeft    = cbDMA;
     805
     806                if (cbDMALeft > RTCircBufFree(pCircBuf))
     807                {
     808                    LogRel2(("HDA: FIFO overflow for stream #%RU8 (%RU32 bytes outstanding)\n",
     809                             pStream->u8SD, cbDMALeft - RTCircBufFree(pCircBuf)));
     810
     811                    /* Try to read as much as possible. */
     812                    cbDMALeft = (uint32_t)RTCircBufFree(pCircBuf);
     813
     814                    rc = VERR_BUFFER_OVERFLOW;
     815                }
     816
     817                while (cbDMALeft)
     818                {
     819                    void *pvBuf; size_t cbBuf;
     820                    RTCircBufAcquireWriteBlock(pCircBuf, cbDMALeft, &pvBuf, &cbBuf);
     821
     822                    if (cbBuf)
     823                        memcpy(pvBuf, abChunk + cbDMAWritten, cbBuf);
     824
     825                    RTCircBufReleaseWriteBlock(pCircBuf, cbBuf);
     826
     827                    cbDMALeft    -= (uint32_t)cbBuf;
     828                    cbDMAWritten += (uint32_t)cbBuf;
     829                }
     830            }
     831            else
    668832                LogRel(("HDA: Reading from stream #%RU8 DMA failed with %Rrc\n", pStream->u8SD, rc));
    669833
    670834            STAM_PROFILE_STOP(&pThis->StatOut, a);
    671835        }
    672         else if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN) /* Input (SDI). */
    673         {
    674             STAM_PROFILE_START(&pThis->StatIn, a);
    675 
    676             rc = hdaDMAWrite(pThis, pStream, cbChunk, &cbDMA /* pcbWritten */);
    677             if (RT_FAILURE(rc))
    678                 LogRel(("HDA: Writing to stream #%RU8 DMA failed with %Rrc\n", pStream->u8SD, rc));
    679 
    680             STAM_PROFILE_STOP(&pThis->StatIn, a);
    681         }
     836
    682837        else /** @todo Handle duplex streams? */
    683838            AssertFailed();
     
    692847            Assert(pBDLE->State.u32BufOff <= pBDLE->Desc.u32BufSize);
    693848
    694             hdaStreamTransferInc(pStream, cbDMA);
    695 
    696             uint32_t framesDMA = cbDMA / HDA_FRAME_SIZE;
    697 
    698             /* Add the transferred frames to the period. */
    699             hdaStreamPeriodInc(pPeriod, framesDMA);
    700 
    701             /* Save the timestamp of when the last successful DMA transfer has been for this stream. */
    702             pStream->State.uTimerTS = TMTimerGet(pThis->pTimer);
    703 
    704             Assert(cbLeft >= cbDMA);
    705             cbLeft        -= cbDMA;
     849            /* Are we done doing the position adjustment?
     850             * Only then do the transfer accounting .*/
     851            if (pStream->State.cPosAdjustFramesLeft == 0)
     852            {
     853                Assert(cbLeft >= cbDMA);
     854                cbLeft        -= cbDMA;
     855
     856                cbProcessed   += cbDMA;
     857            }
     858
     859            /**
     860             * Update the stream's current position.
     861             * Do this as accurate and close to the actual data transfer as possible.
     862             * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters).
     863             */
     864            uint32_t cbStreamPos = hdaStreamGetPosition(pThis, pStream);
     865            if (cbStreamPos == pStream->u32CBL)
     866                cbStreamPos = 0;
     867
     868            hdaStreamSetPosition(pStream, cbStreamPos + cbDMA);
    706869        }
    707870
     
    710873            Log3Func(("[SD%RU8] Complete: %R[bdle]\n", pStream->u8SD, pBDLE));
    711874
    712             if (hdaBDLENeedsInterrupt(pBDLE))
     875                /* Does the current BDLE require an interrupt to be sent? */
     876            if (   hdaBDLENeedsInterrupt(pBDLE)
     877                /* Are we done doing the position adjustment?
     878                 * It can happen that a BDLE which is handled while doing the
     879                 * position adjustment requires an interrupt on completion (IOC) being set.
     880                 *
     881                 * In such a case we need to skip such an interrupt and just move on. */
     882                && pStream->State.cPosAdjustFramesLeft == 0)
    713883            {
    714884                /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL register is set
     
    716886                 */
    717887                if (HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_SDCTL_IOCE)
    718                     hdaStreamPeriodAcquireInterrupt(pPeriod);
     888                {
     889                    pStream->State.cTransferPendingInterrupts++;
     890
     891                    AssertMsg(pStream->State.cTransferPendingInterrupts <= 32,
     892                              ("Too many pending interrupts (%RU8) for stream #%RU8\n",
     893                               pStream->State.cTransferPendingInterrupts, pStream->u8SD));
     894                }
    719895            }
    720896
    721897            if (pStream->State.uCurBDLE == pStream->u16LVI)
    722898            {
    723                 Assert(pStream->u32CBL == HDA_STREAM_REG(pThis, LPIB, pStream->u8SD));
    724 
    725899                pStream->State.uCurBDLE = 0;
    726                 hdaStreamUpdateLPIB(pStream, 0 /* LPIB */);
    727900            }
    728901            else
    729902                pStream->State.uCurBDLE++;
    730903
     904            /* Fetch the next BDLE entry. */
    731905            hdaBDLEFetch(pThis, pBDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
    732 
    733             Log3Func(("[SD%RU8] Fetching: %R[bdle]\n", pStream->u8SD, pBDLE));
    734906        }
     907
     908        /* Do the position adjustment accounting. */
     909        pStream->State.cPosAdjustFramesLeft -= RT_MIN(pStream->State.cPosAdjustFramesLeft, cbDMA / HDA_FRAME_SIZE);
    735910
    736911        if (RT_FAILURE(rc))
     
    738913    }
    739914
    740     if (hdaStreamPeriodIsComplete(pPeriod))
    741     {
    742         Log3Func(("[SD%RU8] Period complete -- Current: %R[bdle]\n", pStream->u8SD, &pStream->State.BDLE));
    743 
    744         /* Set the stream's BCIS bit.
     915    Log3Func(("[SD%RU8] cbToProcess=%RU32, cbProcessed=%RU32, cbLeft=%RU32, %R[bdle], rc=%Rrc\n",
     916              pStream->u8SD, cbToProcess, cbProcessed, cbLeft, pBDLE, rc));
     917
     918    /* Sanity. */
     919    Assert(cbProcessed % HDA_FRAME_SIZE == 0);
     920    Assert(cbProcessed == cbToProcess);
     921    Assert(cbLeft      == 0);
     922
     923    /* Only do the data accounting if we don't have to do any position
     924     * adjustment anymore. */
     925    if (pStream->State.cPosAdjustFramesLeft == 0)
     926    {
     927        hdaStreamPeriodInc(pPeriod, RT_MIN(cbProcessed / HDA_FRAME_SIZE, hdaStreamPeriodGetRemainingFrames(pPeriod)));
     928
     929        pStream->State.cbTransferProcessed += cbProcessed;
     930    }
     931
     932    /* Make sure that we never report more stuff processed than initially announced. */
     933    if (pStream->State.cbTransferProcessed > pStream->State.cbTransferSize)
     934        pStream->State.cbTransferProcessed = pStream->State.cbTransferSize;
     935
     936    uint32_t cbTransferLeft     = pStream->State.cbTransferSize - pStream->State.cbTransferProcessed;
     937    bool     fTransferComplete  = !cbTransferLeft;
     938    uint64_t tsTransferNext     = 0;
     939
     940    if (fTransferComplete)
     941    {
     942        /**
     943         * Try updating the wall clock.
     944         *
     945         * Note 1) Only certain guests (like Linux' snd_hda_intel) rely on the WALCLK register
     946         *         in order to determine the correct timing of the sound device. Other guests
     947         *         like Windows 7 + 10 (or even more exotic ones like Haiku) will completely
     948         *         ignore this.
     949         *
     950         * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic
     951         *         fashion) this *will* upset guest device drivers and will completely fuck up the
     952         *         sound output. Running VLC on the guest will tell!
     953         */
     954        const bool fWalClkSet = hdaWalClkSet(pThis,
     955                                               hdaWalClkGetCurrent(pThis)
     956                                             + hdaStreamPeriodFramesToWalClk(pPeriod, pStream->State.cbTransferProcessed / HDA_FRAME_SIZE),
     957                                             false /* fForce */);
     958        RT_NOREF(fWalClkSet);
     959    }
     960
     961    /* Does the period have any interrupts outstanding? */
     962    if (pStream->State.cTransferPendingInterrupts)
     963    {
     964        Log3Func(("[SD%RU8] Scheduling interrupt\n", pStream->u8SD));
     965
     966        /**
     967         * Set the stream's BCIS bit.
    745968         *
    746969         * Note: This only must be done if the whole period is complete, and not if only
     
    750973         * 2) reads SDSTS (with BCIS set) and then 3) too early reads a (wrong) WALCLK value.
    751974         *
    752          * snd_hda_intel on Linux will tell. */
     975         * snd_hda_intel on Linux will tell.
     976         */
    753977        HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_SDSTS_BCIS;
    754978
    755         /* Try updating the wall clock. */
    756         const uint64_t u64WalClk  = hdaStreamPeriodGetAbsElapsedWalClk(pPeriod);
    757         const bool     fWalClkSet = hdaWalClkSet(pThis, u64WalClk, false /* fForce */);
    758 
    759         /* Does the period have any interrupts outstanding? */
    760         if (hdaStreamPeriodNeedsInterrupt(pPeriod))
    761         {
    762             if (fWalClkSet)
    763             {
    764                 Log3Func(("[SD%RU8] Set WALCLK to %RU64, triggering interrupt\n", pStream->u8SD, u64WalClk));
    765 
    766                 /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with
    767                  * ending / beginning a period. */
     979        /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with
     980         * ending / beginning a period. */
    768981#ifndef DEBUG
    769                 hdaProcessInterrupt(pThis);
     982        hdaProcessInterrupt(pThis);
    770983#else
    771                 hdaProcessInterrupt(pThis, __FUNCTION__);
     984        hdaProcessInterrupt(pThis, __FUNCTION__);
    772985#endif
    773             }
     986        pStream->State.cTransferPendingInterrupts--;
     987    }
     988    else /* Transfer still in-flight -- schedule the next timing slot. */
     989    {
     990        uint32_t cbTransferNext = cbTransferLeft;
     991
     992        /* No data left to transfer anymore or do we have more data left
     993         * than we can transfer per timing slot? Clamp. */
     994        if (   !cbTransferNext
     995            || cbTransferNext > pStream->State.cbTransferChunk)
     996        {
     997            cbTransferNext = pStream->State.cbTransferChunk;
    774998        }
    775         else
    776         {
    777             /* End the period first ... */
    778             hdaStreamPeriodEnd(pPeriod);
    779 
    780             /* ... and immediately begin the next one. */
    781             hdaStreamPeriodBegin(pPeriod, hdaWalClkGetCurrent(pThis));
    782         }
    783     }
     999
     1000        tsTransferNext = tsNow + (cbTransferNext * pStream->State.cTicksPerByte);
     1001    }
     1002
     1003    /* If we need to do another transfer, (re-)arm the device timer.  */
     1004    if (tsTransferNext) /* Can be 0 if no next transfer is needed. */
     1005    {
     1006        Log3Func(("[SD%RU8] Scheduling timer\n", pStream->u8SD));
     1007
     1008        TMTimerUnlock(pThis->pTimer);
     1009
     1010        hdaTimerSet(pThis, tsTransferNext, false /* fForce */);
     1011
     1012        TMTimerLock(pThis->pTimer, VINF_SUCCESS);
     1013
     1014        pStream->State.tsTransferNext = tsTransferNext;
     1015    }
     1016
     1017    pStream->State.tsTransferLast = tsNow;
     1018
     1019    Log3Func(("[SD%RU8] cbTransferLeft=%RU32 -- %RU64/%RU64\n",
     1020              pStream->u8SD, cbTransferLeft, pStream->State.cbTransferProcessed, pStream->State.cbTransferSize));
     1021    Log3Func(("[SD%RU8] fTransferComplete=%RTbool, cTransferPendingInterrupts=%RU8\n",
     1022              pStream->u8SD, fTransferComplete, pStream->State.cTransferPendingInterrupts));
     1023    Log3Func(("[SD%RU8] tsNow=%RU64, tsTransferNext=%RU64 (in %RU64 ticks)\n",
     1024              pStream->u8SD, tsNow, tsTransferNext, tsTransferNext - tsNow));
    7841025
    7851026    hdaStreamPeriodUnlock(pPeriod);
    786 
    787     Log3Func(("[SD%RU8] Returning %Rrc ==========================================\n", pStream->u8SD, rc));
    788 
    789     if (RT_FAILURE(rc))
    790         LogFunc(("[SD%RU8] Failed with rc=%Rrcc\n", pStream->u8SD, rc));
    791 
    7921027    hdaStreamUnlock(pStream);
    7931028
     
    8621097
    8631098            /* When running synchronously, update the associated sink here.
    864              * Otherwise this will be done in the device timer. */
     1099             * Otherwise this will be done in the stream's dedicated async I/O thread. */
    8651100            rc2 = AudioMixerSinkUpdate(pSink);
    8661101            AssertRC(rc2);
     
    8751110        if (fInTimer)
    8761111        {
    877             rc2 = hdaStreamAsyncIONotify(pStream);
    878             AssertRC(rc2);
    879         }
    880         else
    881         {
    8821112#endif
    8831113            rc2 = AudioMixerSinkUpdate(pSink);
     
    8851115
    8861116            /* Is the sink ready to be read (host input data) from? If so, by how much? */
    887             const uint32_t cbReadable = AudioMixerSinkGetReadable(pSink);
    888 
    889             /* How much (guest input) data is free at the moment? */
    890             uint32_t cbFree = hdaStreamGetFree(pStream);
    891 
    892             Log3Func(("[SD%RU8] cbReadable=%RU32, cbFree=%RU32\n", pStream->u8SD, cbReadable, cbFree));
    893 
    894             /* Do not read more than the sink can provide at the moment.
    895              * The host sets the overall pace. */
    896             if (cbFree > cbReadable)
    897                 cbFree = cbReadable;
    898 
    899             if (cbFree)
    900             {
    901                 /* Write (guest input) data to the stream which was read from stream's sink before. */
    902                 rc2 = hdaStreamWrite(pStream, cbFree, NULL /* pcbWritten */);
    903                 AssertRC(rc2);
    904             }
    905 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    906         }
    907 #endif
    908 
    909 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    910         if (fInTimer)
    911         {
    912 #endif
     1117            uint32_t cbReadable = AudioMixerSinkGetReadable(pSink);
     1118
     1119            Log3Func(("[SD%RU8] cbReadable=%RU32\n", pStream->u8SD, cbReadable));
     1120
     1121            if (cbReadable)
     1122            {
     1123                uint8_t abFIFO[HDA_FIFO_MAX + 1];
     1124                while (cbReadable)
     1125                {
     1126                    uint32_t cbRead;
     1127                    rc2 = AudioMixerSinkRead(pSink, AUDMIXOP_COPY,
     1128                                             abFIFO, RT_MIN(cbReadable, (uint32_t)sizeof(abFIFO)), &cbRead);
     1129                    AssertRCBreak(rc2);
     1130
     1131                    /* Write (guest input) data to the stream which was read from stream's sink before. */
     1132                    rc2 = hdaStreamWrite(pStream, abFIFO, cbRead, NULL /* pcbWritten */);
     1133                    AssertRCBreak(rc2);
     1134
     1135                    Assert(cbReadable >= cbRead);
     1136                    cbReadable -= cbRead;
     1137                }
     1138            }
     1139        #if 0
     1140            else /* Send silence as input. */
     1141            {
     1142                cbReadable = pStream->State.cbTransferSize - pStream->State.cbTransferProcessed;
     1143
     1144                Log3Func(("[SD%RU8] Sending silence (%RU32 bytes)\n", pStream->u8SD, cbReadable));
     1145
     1146                if (cbReadable)
     1147                {
     1148                    rc2 = hdaStreamWrite(pStream, NULL /* Silence */, cbReadable, NULL /* pcbWritten */);
     1149                    AssertRC(rc2);
     1150                }
     1151            }
     1152        #endif
     1153
    9131154            const uint32_t cbToTransfer = hdaStreamGetUsed(pStream);
    9141155            if (cbToTransfer)
    9151156            {
    916                 /* When running synchronously, do the DMA data transfers here.
    917                  * Otherwise this will be done in the stream's async I/O thread. */
    9181157                rc2 = hdaStreamTransfer(pStream, cbToTransfer);
    9191158                AssertRC(rc2);
    9201159            }
    9211160#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    922         }
     1161        } /* fInTimer */
    9231162#endif
    9241163    }
  • trunk/src/VBox/Devices/Audio/HDAStream.h

    r69119 r69919  
    109109    /** Circular buffer (FIFO) for holding DMA'ed data. */
    110110    R3PTRTYPE(PRTCIRCBUF)   pCircBuf;
    111     /** Timestamp of the last success DMA data transfer.
    112      *  Used to calculate the time actually elapsed between two transfers. */
    113     uint64_t                uTimerTS;
     111    /** Timestamp of the last DMA data transfer. */
     112    uint64_t                tsTransferLast;
     113    /** Timestamp of the next DMA data transfer.
     114     *  Next for determining the next scheduling window.
     115     *  Can be 0 if no next transfer is scheduled. */
     116    uint64_t                tsTransferNext;
     117    /** Total transfer size (in bytes) of a transfer period. */
     118    uint32_t                cbTransferSize;
     119    /** Transfer chunk size (in bytes) of a transfer period. */
     120    uint32_t                cbTransferChunk;
     121    /** How many bytes already have been processed in within
     122     *  the current transfer period. */
     123    uint32_t                cbTransferProcessed;
     124    /** How many interrupts are pending due to
     125     *  BDLE interrupt-on-completion (IOC) bits set. */
     126    uint8_t                 cTransferPendingInterrupts;
     127    uint8_t                 Padding1[4];
     128    /** How many audio data frames are left to be processed
     129     *  for the position adjustment handling.
     130     *
     131     *  0 if position adjustment handling is done or inactive. */
     132    uint16_t                cPosAdjustFramesLeft;
     133    uint8_t                 Padding2[2];
     134    /** (Virtual) clock ticks per byte. */
     135    uint64_t                cTicksPerByte;
     136    /** (Virtual) clock ticks per transfer. */
     137    uint64_t                cTransferTicks;
    114138    /** The stream's period. Need for timing. */
    115139    HDASTREAMPERIOD         Period;
     
    122146#endif
    123147    /** Unused, padding. */
    124     uint8_t                 Padding1[3];
     148    uint8_t                 Padding3[3];
    125149} HDASTREAMSTATE, *PHDASTREAMSTATE;
    126150
     
    193217void              hdaStreamReset(PHDASTATE pThis, PHDASTREAM pStream, uint8_t uSD);
    194218int               hdaStreamEnable(PHDASTREAM pStream, bool fEnable);
     219uint32_t          hdaStreamGetPosition(PHDASTATE pThis, PHDASTREAM pStream);
     220void              hdaStreamSetPosition(PHDASTREAM pStream, uint32_t u32LPIB);
     221uint32_t          hdaStreamGetFree(PHDASTREAM pStream);
    195222uint32_t          hdaStreamGetUsed(PHDASTREAM pStream);
    196 uint32_t          hdaStreamGetFree(PHDASTREAM pStream);
     223bool              hdaStreamTransferIsScheduled(PHDASTREAM pStream);
     224uint64_t          hdaStreamTransferGetNext(PHDASTREAM pStream);
    197225int               hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax);
    198 uint32_t          hdaStreamUpdateLPIB(PHDASTREAM pStream, uint32_t u32LPIB);
    199226void              hdaStreamLock(PHDASTREAM pStream);
    200227void              hdaStreamUnlock(PHDASTREAM pStream);
    201228int               hdaStreamRead(PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead);
    202 int               hdaStreamWrite(PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten);
     229int               hdaStreamWrite(PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
    203230void              hdaStreamUpdate(PHDASTREAM pStream, bool fAsync);
    204231# ifdef HDA_USE_DMA_ACCESS_HANDLER
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