Changeset 69919 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Dec 4, 2017 2:00:05 PM (7 years ago)
- svn:sync-xref-src-repo-rev:
- 119399
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHDA.cpp
r69719 r69919 229 229 static int hdaRegWriteCORBRP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); 230 230 static int hdaRegWriteCORBCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); 231 static int hdaRegWriteCORBSIZE(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); 231 232 static int hdaRegWriteCORBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); 233 static int hdaRegWriteRINTCNT(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value); 232 234 static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); 233 235 static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); … … 281 283 * @{ 282 284 */ 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 286 static void hdaTimerMain(PHDASTATE pThis); 287 287 #endif 288 288 /** @} */ … … 351 351 { 0x00044, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, HDA_RD_FLAG_NONE, hdaRegReadU32 , hdaRegWriteBase , HDA_REG_IDX(CORBUBASE) }, /* CORB Upper Base Address */ 352 352 { 0x00048, 0x00002, 0x000000FF, 0x000000FF, HDA_RD_FLAG_NONE, hdaRegReadU16 , hdaRegWriteCORBWP , HDA_REG_IDX(CORBWP) }, /* CORB Write Pointer */ 353 { 0x0004A, 0x00002, 0x000080FF, 0x000080 FF, 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 */ 354 354 { 0x0004C, 0x00001, 0x00000003, 0x00000003, HDA_RD_FLAG_NONE, hdaRegReadU8 , hdaRegWriteCORBCTL , HDA_REG_IDX(CORBCTL) }, /* CORB Control */ 355 355 { 0x0004D, 0x00001, 0x00000001, 0x00000001, HDA_RD_FLAG_NONE, hdaRegReadU8 , hdaRegWriteCORBSTS , HDA_REG_IDX(CORBSTS) }, /* CORB Status */ 356 { 0x0004E, 0x00001, 0x000000F3, 0x0000000 0, 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 */ 357 357 { 0x00050, 0x00004, 0xFFFFFF80, 0xFFFFFF80, HDA_RD_FLAG_NONE, hdaRegReadU32 , hdaRegWriteBase , HDA_REG_IDX(RIRBLBASE) }, /* RIRB Lower Base Address */ 358 358 { 0x00054, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, HDA_RD_FLAG_NONE, hdaRegReadU32 , hdaRegWriteBase , HDA_REG_IDX(RIRBUBASE) }, /* RIRB Upper Base Address */ 359 359 { 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 , hdaRegWrite U16, 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 */ 361 361 { 0x0005C, 0x00001, 0x00000007, 0x00000007, HDA_RD_FLAG_NONE, hdaRegReadU8 , hdaRegWriteU8 , HDA_REG_IDX(RIRBCTL) }, /* RIRB Control */ 362 362 { 0x0005D, 0x00001, 0x00000005, 0x00000005, HDA_RD_FLAG_NONE, hdaRegReadU8 , hdaRegWriteRIRBSTS , HDA_REG_IDX(RIRBSTS) }, /* RIRB Status */ … … 436 436 SSMFIELD_ENTRY(HDASTREAMSTATE, uCurBDLE), 437 437 SSMFIELD_ENTRY(HDASTREAMSTATE, fInReset), 438 SSMFIELD_ENTRY(HDASTREAMSTATE, uTimerTS),438 SSMFIELD_ENTRY(HDASTREAMSTATE, tsTransferNext), 439 439 SSMFIELD_ENTRY_TERM() 440 440 }; … … 723 723 if (fLocal) 724 724 { 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 } 733 734 } 734 735 else 735 736 { 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 } 740 746 } 741 747 … … 791 797 static int hdaCORBCmdProcess(PHDASTATE pThis) 792 798 { 793 int rc = hdaCmdSync(pThis, true /* Sync from guest */);794 AssertRCReturn(rc, rc);795 796 799 uint8_t corbRp = HDA_REG(pThis, CORBRP); 797 800 uint8_t corbWp = HDA_REG(pThis, CORBWP); … … 800 803 Log3Func(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", corbRp, corbWp, rirbWp)); 801 804 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 802 824 while (corbRp != corbWp) 803 825 { 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]; 806 829 uint64_t uResp = 0; 807 uint32_t uCmd = pThis->pu32CorbBuf[corbRp];808 830 809 831 rc = pThis->pCodec->pfnLookup(pThis->pCodec, HDA_CODEC_CMD(uCmd, 0 /* Codec index */), &uResp); … … 811 833 LogFunc(("Codec lookup failed with rc=%Rrc\n", rc)); 812 834 813 Log Func(("verb:%08x ->%016lx\n", uCmd, uResp));835 Log3Func(("Codec verb %08x -> response %016lx\n", uCmd, uResp)); 814 836 815 837 if ( (uResp & CODEC_RESPONSE_UNSOLICITED) … … 828 850 829 851 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)); 837 886 838 887 HDA_REG(pThis, CORBRP) = corbRp; … … 841 890 rc = hdaCmdSync(pThis, false /* Sync to guest */); 842 891 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 DEBUG854 rc = hdaProcessInterrupt(pThis);855 #else856 rc = hdaProcessInterrupt(pThis, __FUNCTION__);857 #endif858 pThis->u16RespIntCnt--;859 }860 else /* Not enabled -- just reset our internal counter. */861 pThis->u16RespIntCnt = 0;862 }863 892 864 893 if (RT_FAILURE(rc)) … … 1089 1118 static int hdaRegWriteCORBRP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) 1090 1119 { 1091 RT_NOREF _PV(iReg);1120 RT_NOREF(iReg); 1092 1121 1093 1122 DEVHDA_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); 1094 1123 1095 1124 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 1096 1135 HDA_REG(pThis, CORBRP) = HDA_CORBRP_RST; /* Clears the pointer. */ 1136 } 1097 1137 else 1098 1138 HDA_REG(pThis, CORBRP) &= ~HDA_CORBRP_RST; /* Only CORBRP_RST bit is writable. */ … … 1105 1145 { 1106 1146 #ifdef IN_RING3 1147 DEVHDA_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); 1148 1107 1149 int rc = hdaRegWriteU8(pThis, iReg, u32Value); 1108 1150 AssertRC(rc); 1109 1151 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. */ 1114 1153 { 1115 1154 rc = hdaCORBCmdProcess(pThis); 1116 1155 } 1156 else 1157 LogFunc(("CORB DMA not running, skipping\n")); 1117 1158 1118 1159 DEVHDA_UNLOCK(pThis); 1119 1120 1160 return rc; 1121 1161 #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 1167 static 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); 1123 1234 return VINF_IOM_R3_MMIO_WRITE; 1124 1235 #endif … … 1135 1246 1136 1247 DEVHDA_UNLOCK(pThis); 1137 1138 1248 return VINF_SUCCESS; 1139 1249 } … … 1142 1252 { 1143 1253 #ifdef IN_RING3 1254 DEVHDA_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); 1255 1144 1256 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); 1160 1259 1161 1260 rc = hdaCORBCmdProcess(pThis); 1162 1261 1163 1262 DEVHDA_UNLOCK(pThis); 1164 1165 1263 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); 1168 1266 return VINF_IOM_R3_MMIO_WRITE; 1169 #endif /* IN_RING3 */1267 #endif 1170 1268 } 1171 1269 … … 1306 1404 1307 1405 /* Enable/disable the stream. */ 1308 hdaStreamEnable(pStream, fRun /* fEnable */); 1406 rc2 = hdaStreamEnable(pStream, fRun /* fEnable */); 1407 AssertRC(rc2); 1309 1408 1310 1409 if (fRun) 1311 1410 { 1411 /* Keep track of running streams. */ 1412 pThis->cStreamsActive++; 1413 1312 1414 /* (Re-)init the stream's period. */ 1313 1415 hdaStreamPeriodInit(&pStream->State.Period, … … 1316 1418 /* Begin a new period for this stream. */ 1317 1419 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 */); 1318 1423 AssertRC(rc2); 1319 1424 } 1320 1425 else 1321 1426 { 1427 /* Keep track of running streams. */ 1428 Assert(pThis->cStreamsActive); 1429 if (pThis->cStreamsActive) 1430 pThis->cStreamsActive--; 1431 1322 1432 /* Make sure to (re-)schedule outstanding (delayed) interrupts. */ 1323 1433 hdaReschedulePendingInterrupts(pThis); … … 1332 1442 /* Make sure to leave the lock before (eventually) starting the timer. */ 1333 1443 hdaStreamUnlock(pStream); 1334 1335 # ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS1336 /* See if we need to start or stop the timer. */1337 if (!fRun)1338 hdaTimerMaybeStop(pThis);1339 else1340 hdaTimerMaybeStart(pThis);1341 # endif1342 1444 } 1343 1445 } … … 1358 1460 { 1359 1461 #ifdef IN_RING3 1360 DEVHDA_LOCK (pThis);1462 DEVHDA_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); 1361 1463 1362 1464 PHDASTREAM pStream = hdaGetStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, STS, iReg)); … … 1366 1468 HDA_SD_NUM_FROM_REG(pThis, STS, iReg), u32Value)); 1367 1469 1368 DEVHDA_UNLOCK (pThis);1470 DEVHDA_UNLOCK_BOTH(pThis); 1369 1471 return hdaRegWriteU16(pThis, iReg, u32Value); 1370 1472 } … … 1391 1493 if (hdaStreamPeriodIsComplete(pPeriod)) 1392 1494 { 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 1393 1501 hdaStreamPeriodEnd(pPeriod); 1394 1502 … … 1398 1506 1399 1507 hdaStreamPeriodUnlock(pPeriod); /* Unlock before processing interrupt. */ 1400 1401 if (fNeedsInterrupt) 1402 { 1508 } 1509 1403 1510 #ifndef DEBUG 1404 1511 hdaProcessInterrupt(pThis); 1405 1512 #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); 1412 1555 return VINF_SUCCESS; 1413 1556 #else /* IN_RING3 */ … … 1998 2141 static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) 1999 2142 { 2000 RT_NOREF _PV(iReg);2143 RT_NOREF(iReg); 2001 2144 2002 2145 DEVHDA_LOCK_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE); 2003 2146 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 2004 2155 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 2005 2166 HDA_REG(pThis, RIRBWP) = 0; 2167 } 2006 2168 2007 2169 DEVHDA_UNLOCK(pThis); … … 2009 2171 /* The remaining bits are O, see 6.2.22. */ 2010 2172 return VINF_SUCCESS; 2173 } 2174 2175 static 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; 2011 2196 } 2012 2197 … … 2515 2700 } 2516 2701 2517 #ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS2518 /**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 might2592 * be queued audio data which needs to be handled (e.g. played back) first2593 * 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 and2603 * then checks if the internal audio device timer can be2604 * 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 2627 2702 /** 2628 2703 * Main routine for the device timer. … … 2638 2713 DEVHDA_LOCK_BOTH_RETURN_VOID(pThis); 2639 2714 2715 /* Do all transfers from/to DMA. */ 2716 hdaDoTransfers(pThis); 2717 2640 2718 /* Flag indicating whether to kick the timer again for a 2641 2719 * new data processing round. */ 2642 bool fKickTimer = false; 2643 2644 hdaDoTransfers(pThis); 2720 bool fSinksActive = false; 2645 2721 2646 2722 /* Do we need to kick the timer again? */ … … 2656 2732 ) 2657 2733 { 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 } 2671 2754 2672 2755 DEVHDA_UNLOCK_BOTH(pThis); … … 2727 2810 uint64_t cbWrittenHz = ASMAtomicReadU64(&pStreamDbg->cbWrittenHz); 2728 2811 2729 if (tsElapsedMs >= (1000 / HDA_TIMER_HZ ))2812 if (tsElapsedMs >= (1000 / HDA_TIMER_HZ_DEFAULT)) 2730 2813 { 2731 2814 LogFunc(("[SD%RU8] %RU32ms elapsed, cbWritten=%RU64, cWritten=%RU64 -- %RU32 bytes on average per time slot (%zums)\n", 2732 2815 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)); 2734 2817 2735 2818 pStreamDbg->tsWriteSlotBegin = tsNowNs; … … 2817 2900 LogFlowFuncEnter(); 2818 2901 2819 # ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS2820 /*2821 * Stop the timer, if any.2822 */2823 hdaTimerStop(pThis);2824 2825 2902 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 */ 2843 2911 HDA_REG(pThis, CORBRP) = 0x0; 2912 HDA_REG(pThis, CORBWP) = 0x0; 2844 2913 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; 2846 2917 2847 2918 /* … … 2872 2943 } 2873 2944 2874 /*2945 /* 2875 2946 * Set some sensible defaults for which HDA sinks 2876 2947 * are connected to which stream number. … … 2923 2994 } 2924 2995 2925 2926 2996 /** 2927 2997 * Timer callback which handles the audio data transfers on a periodic basis. … … 2942 3012 } 2943 3013 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 2994 3014 /** 2995 3015 * Main routine to perform the actual audio data transfers from the HDA streams … … 3005 3025 #endif 3006 3026 PHDASTREAM pStreamFront = hdaGetStreamFromSink(pThis, &pThis->SinkFront); 3007 #ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND3008 /** @todo See note below. */3009 #endif3010 3027 3011 3028 hdaStreamUpdate(pStreamFront, true /* fInTimer */); … … 3534 3551 int rc = VINF_SUCCESS; 3535 3552 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. */ 3537 3554 3538 3555 /* … … 3557 3574 hdaStreamAsyncIOEnable(pStream, true /* fEnable */); 3558 3575 #endif 3559 /* (Re-)initialize the stream with current values. */3560 rc2 = hdaStreamInit(pStream, pStream->u8SD);3561 AssertRC(rc2);3562 3563 3576 /* Resume the stream's period. */ 3564 3577 hdaStreamPeriodResume(&pStream->State.Period); … … 3576 3589 hdaStreamRegisterDMAHandlers(pThis, pStream); 3577 3590 #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)); 3579 3598 } 3580 3599 } 3581 3600 } 3582 3601 3583 #ifndef VBOX_WITH_AUDIO_CALLBACKS3584 3602 /* 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 } 3588 3608 3589 3609 LogFlowFuncLeaveRC(rc); … … 3973 3993 } 3974 3994 3975 /*3976 * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.3977 */3978 3995 rc = SSMR3GetStructEx(pSSM, &pStrm->State, sizeof(HDASTREAMSTATE), 3979 3996 0 /* fFlags */, g_aSSMStreamStateFields7, … … 3981 3998 AssertRC(rc); 3982 3999 4000 /* 4001 * Load BDLEs (Buffer Descriptor List Entries) and DMA counters. 4002 */ 3983 4003 rc = SSMR3GetStructEx(pSSM, &pStrm->State.BDLE.Desc, sizeof(HDABDLEDESC), 3984 4004 0 /* fFlags */, g_aSSMBDLEDescFields7, NULL); … … 4009 4029 * Load internal (FIFO) buffer. 4010 4030 */ 4011 4012 4031 uint32_t cbCircBufSize = 0; 4013 4032 rc = SSMR3GetU32(pSSM, &cbCircBufSize); /* cbCircBuf */ … … 4731 4750 if (!CFGMR3AreValuesValid(pCfg, "R0Enabled\0" 4732 4751 "RCEnabled\0" 4733 "TimerHz\0")) 4752 "TimerHz\0" 4753 "PosAdjustEnabled\0" 4754 "PosAdjustFrames\0")) 4755 { 4734 4756 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, 4735 4757 N_ ("Invalid configuration for the Intel HDA device")); 4758 } 4736 4759 4737 4760 int rc = CFGMR3QueryBoolDef(pCfg, "RCEnabled", &pThis->fRCEnabled, false); … … 4743 4766 return PDMDEV_SET_ERROR(pDevIns, rc, 4744 4767 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. */); 4748 4770 if (RT_FAILURE(rc)) 4749 4771 return PDMDEV_SET_ERROR(pDevIns, rc, 4750 4772 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)); 4752 4792 4753 4793 /* … … 5174 5214 } 5175 5215 5176 # ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS5177 5216 if (RT_SUCCESS(rc)) 5178 5217 { … … 5191 5230 rc = TMR3TimerSetCritSect(pThis->pTimer, &pThis->CritSect); 5192 5231 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 } 5228 5233 5229 5234 # ifdef VBOX_WITH_STATISTICS … … 5233 5238 * Register statistics. 5234 5239 */ 5235 # ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS5236 5240 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer, STAMTYPE_PROFILE, "/Devices/HDA/Timer", STAMUNIT_TICKS_PER_CALL, "Profiling hdaTimer."); 5237 # endif5238 5241 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatIn, STAMTYPE_PROFILE, "/Devices/HDA/Input", STAMUNIT_TICKS_PER_CALL, "Profiling input."); 5239 5242 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatOut, STAMTYPE_PROFILE, "/Devices/HDA/Output", STAMUNIT_TICKS_PER_CALL, "Profiling output."); -
trunk/src/VBox/Devices/Audio/DevHDA.h
r69719 r69919 154 154 /** Number of active (running) SDn streams. */ 155 155 uint8_t cStreamsActive; 156 #ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS157 156 /** The timer for pumping data thru the attached LUN drivers. */ 158 157 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 #endif167 158 #ifdef VBOX_WITH_STATISTICS 168 # ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS169 159 STAMPROFILE StatTimer; 170 # endif171 160 STAMPROFILE StatIn; 172 161 STAMPROFILE StatOut; … … 205 194 /** Response Interrupt Count (RINTCNT). */ 206 195 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]; 207 210 /** Current IRQ level. */ 208 211 uint8_t u8IRQL; 212 /** The device timer Hz rate. Defaults to HDA_TIMER_HZ_DEFAULT. */ 213 uint16_t u16TimerHz; 209 214 /** Padding for alignment. */ 210 uint8_t au8Padding3[ 5];215 uint8_t au8Padding3[3]; 211 216 #ifdef DEBUG 212 217 HDASTATEDBGINFO Dbg; 213 218 #endif 214 219 } HDASTATE, *PHDASTATE; 215 216 #ifdef VBOX_WITH_AUDIO_HDA_CALLBACKS217 typedef struct HDACALLBACKCTX218 {219 PHDASTATE pThis;220 PHDADRIVER pDriver;221 } HDACALLBACKCTX, *PHDACALLBACKCTX;222 #endif223 224 220 #endif /* !DEV_HDA_H */ 225 221 -
trunk/src/VBox/Devices/Audio/DevHDACommon.cpp
r69119 r69919 53 53 #endif 54 54 { 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; 58 58 59 59 /* NB: It is possible to have GIS set even when CIE/SIEn are all zero; the GIS bit does 60 60 * not control the interrupt signal. See Figure 4 on page 54 of the HDA 1.0a spec. 61 61 */ 62 63 /* If global interrupt enable (GIE) is set, check if any enabled interrupts are set. */ 62 /* Global Interrupt Enable (GIE) set? */ 64 63 if ( (HDA_REG(pThis, INTCTL) & HDA_INTCTL_GIE) 65 64 && (HDA_REG(pThis, INTSTS) & HDA_REG(pThis, INTCTL) & (HDA_INTCTL_CIE | HDA_STRMINT_MASK))) 66 65 { 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 69 71 #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 102 75 } 103 76 else 104 77 { 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; 138 82 } 139 83 … … 184 128 185 129 #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 189 132 190 133 /* Only drive the WALCLK register forward if all (active) stream periods have passed … … 205 148 /* Get the maximum value of all periods we need to handle. 206 149 * Not the most elegant solution, but works for now ... */ 207 u64WalClk = RT_MAX(u64WalClk Set, u64FrontAbsWalClk);150 u64WalClk = RT_MAX(u64WalClk, u64FrontAbsWalClk); 208 151 #ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND 209 152 # error "Implement me!" 210 153 #endif 211 u64WalClk = RT_MAX(u64WalClk Set, u64LineInAbsWalClk);154 u64WalClk = RT_MAX(u64WalClk, u64LineInAbsWalClk); 212 155 #ifdef VBOX_WITH_HDA_MIC_IN 213 u64WalClk = RT_MAX(u64WalClk Set, u64MicInAbsWalClk);156 u64WalClk = RT_MAX(u64WalClk, u64MicInAbsWalClk); 214 157 #endif 215 158 216 159 #ifdef VBOX_STRICT 217 AssertMsg(u64WalClk Set>= u64WalClkCur,160 AssertMsg(u64WalClk >= u64WalClkCur, 218 161 ("Setting WALCLK to a value going backwards does not make any sense (old %RU64 vs. new %RU64)\n", 219 u64WalClkCur, u64WalClk Set));220 if (u64WalClk Set== u64WalClkCur) /* Setting a stale value? */162 u64WalClkCur, u64WalClk)); 163 if (u64WalClk == u64WalClkCur) /* Setting a stale value? */ 221 164 { 222 165 if (pThis->u8WalClkStaleCnt++ > 3) 223 166 AssertMsgFailed(("Setting WALCLK to a stale value (%RU64) too often isn't a good idea really. " 224 "Good luck with stuck audio stuff.\n", u64WalClk Set));167 "Good luck with stuck audio stuff.\n", u64WalClk)); 225 168 } 226 169 else … … 230 173 231 174 /* Set the new WALCLK value. */ 232 ASMAtomicWriteU64(&pThis->u64WalClk, u64WalClk Set);175 ASMAtomicWriteU64(&pThis->u64WalClk, u64WalClk); 233 176 } 234 177 … … 298 241 299 242 /** 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. 301 244 * 302 245 * @return IPRT status code. 303 246 * @param pThis HDA state. 304 247 * @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. 306 250 * @param pcbRead Returns read bytes from DMA. Optional. 307 251 */ 308 int hdaDMARead(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)252 int hdaDMARead(PHDASTATE pThis, PHDASTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead) 309 253 { 310 254 AssertPtrReturn(pThis, VERR_INVALID_POINTER); … … 312 256 /* pcbRead is optional. */ 313 257 258 PHDABDLE pBDLE = &pStream->State.BDLE; 259 314 260 int rc = VINF_SUCCESS; 315 261 316 262 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); 321 264 322 265 #ifdef HDA_DEBUG_SILENCE … … 327 270 #endif 328 271 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++) 337 285 { 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 343 306 AssertRC(rc2); 344 345 #ifdef HDA_DEBUG_SILENCE346 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 else354 break;355 pu16Buf++;356 }357 #endif358 359 #ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA360 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 else371 AssertRC(rc2);372 }373 #endif374 375 #if 0376 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"));382 307 #endif 383 308 384 309 #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; 402 318 } 403 319 … … 431 347 * @param pThis HDA state. 432 348 * @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. 434 351 * @param pcbWritten Returns written bytes on success. Optional. 435 352 */ 436 int hdaDMAWrite(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)353 int hdaDMAWrite(PHDASTATE pThis, PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 437 354 { 438 355 AssertPtrReturn(pThis, VERR_INVALID_POINTER); … … 440 357 /* pcbWritten is optional. */ 441 358 442 PHDABDLE pBDLE = &pStream->State.BDLE; 443 PRTCIRCBUF pCircBuf = pStream->State.pCircBuf; 444 AssertPtr(pCircBuf); 359 PHDABDLE pBDLE = &pStream->State.BDLE; 445 360 446 361 int rc = VINF_SUCCESS; 447 362 448 363 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); 471 371 472 372 /* Sanity checks. */ 473 Assert(cb Buf<= pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff);474 Assert(cb Buf% HDA_FRAME_SIZE == 0);475 Assert((cb Buf>> 1) >= 1);373 Assert(cbChunk <= pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff); 374 Assert(cbChunk % HDA_FRAME_SIZE == 0); 375 Assert((cbChunk >> 1) >= 1); 476 376 477 377 #ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA … … 479 379 RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaDMAWrite.pcm", 480 380 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 481 RTFileWrite(fh, pvBuf, cb Buf, NULL);381 RTFileWrite(fh, pvBuf, cbChunk, NULL); 482 382 RTFileClose(fh); 483 383 #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; 488 388 489 389 #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; 499 398 } 500 399 … … 707 606 return (pBDLE->Desc.fFlags & HDA_BDLE_FLAG_IOC); 708 607 } 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 */ 626 bool 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 } 709 659 #endif /* IN_RING3 */ 710 660 -
trunk/src/VBox/Devices/Audio/DevHDACommon.h
r69719 r69919 89 89 /** Default timer frequency (in Hz). 90 90 * 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 98 111 99 112 /** HDA's (fixed) audio frame size in bytes. … … 231 244 #define HDA_REG_CORBSIZE 21 /* 0x4E */ 232 245 #define HDA_RMX_CORBSIZE 19 246 #define HDA_CORBSIZE_SZ_CAP 0xF0 247 #define HDA_CORBSIZE_SZ 0x3 233 248 234 249 /** Number of CORB buffer entries. */ 235 250 #define HDA_CORB_SIZE 256 251 /** CORB element size (in bytes). */ 252 #define HDA_CORB_ELEMENT_SIZE 4 236 253 /** Number of RIRB buffer entries. */ 237 254 #define HDA_RIRB_SIZE 256 255 /** RIRB element size (in bytes). */ 256 #define HDA_RIRB_ELEMENT_SIZE 8 238 257 239 258 #define HDA_REG_RIRBLBASE 22 /* 0x50 */ … … 586 605 * @{ 587 606 */ 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);607 int hdaDMARead(PHDASTATE pThis, PHDASTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead); 608 int hdaDMAWrite(PHDASTATE pThis, PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten); 590 609 /** @} */ 591 610 … … 609 628 /** @} */ 610 629 630 /** @name Device timer functions. 631 * @{ 632 */ 633 #ifdef IN_RING3 634 bool hdaTimerSet(PHDASTATE pThis, uint64_t u64Expire, bool fForce); 635 #endif /* IN_RING3 */ 636 /** @} */ 637 611 638 #endif /* !DEV_HDA_H_COMMON */ 612 639 -
trunk/src/VBox/Devices/Audio/HDAStream.cpp
r69119 r69919 92 92 rc2 = hdaStreamAsyncIODestroy(pStream); 93 93 AssertRC(rc2); 94 #else95 RT_NOREF(pThis);96 94 #endif 97 95 … … 137 135 138 136 /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */ 139 hdaStream UpdateLPIB(pStream, HDA_STREAM_REG(pThis, LPIB, pStream->u8SD));137 hdaStreamSetPosition(pStream, HDA_STREAM_REG(pThis, LPIB, pStream->u8SD)); 140 138 141 139 PPDMAUDIOSTREAMCFG pCfg = &pStream->State.Cfg; … … 187 185 LogFunc(("[SD%RU8] DMA @ 0x%x (%RU32 bytes), LVI=%RU16, FIFOS=%RU16, rc=%Rrc\n", 188 186 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 } 189 282 190 283 return rc; … … 239 332 #endif 240 333 334 pStream->State.tsTransferLast = 0; 335 pStream->State.tsTransferNext = 0; 336 241 337 RT_ZERO(pStream->State.BDLE); 242 338 pStream->State.uCurBDLE = 0; … … 304 400 } 305 401 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) 402 uint32_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 */ 415 void hdaStreamSetPosition(PHDASTREAM pStream, uint32_t u32LPIB) 351 416 { 352 417 AssertPtrReturnVoid(pStream); 353 418 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 } 365 435 } 366 436 … … 397 467 } 398 468 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 */ 475 bool 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 */ 494 uint64_t hdaStreamTransferGetNext(PHDASTREAM pStream) 495 { 496 return pStream->State.tsTransferNext; 497 } 399 498 400 499 /** … … 403 502 * @returns IPRT status code. 404 503 * @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. 406 507 * @param pcbWritten Number of bytes written. Optional. 407 508 */ 408 int hdaStreamWrite(PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)509 int hdaStreamWrite(PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 409 510 { 410 511 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 411 AssertReturn(cbToWrite, VERR_INVALID_PARAMETER); 512 /* pvBuf is optional. */ 513 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 412 514 /* 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 }423 515 424 516 PRTCIRCBUF pCircBuf = pStream->State.pCircBuf; … … 428 520 429 521 uint32_t cbWrittenTotal = 0; 430 uint32_t cbLeft = RT_MIN(cb ToWrite, (uint32_t)RTCircBufFree(pCircBuf));522 uint32_t cbLeft = RT_MIN(cbBuf, (uint32_t)RTCircBufFree(pCircBuf)); 431 523 432 524 while (cbLeft) … … 435 527 size_t cbDst; 436 528 437 uint32_t cbRead = 0;438 439 529 RTCircBufAcquireWriteBlock(pCircBuf, cbLeft, &pvDst, &cbDst); 440 530 441 531 if (cbDst) 442 532 { 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 } 448 543 449 544 #ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA … … 451 546 RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaStreamWrite.pcm", 452 547 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 453 RTFileWrite(fh, pvDst, cb Read, NULL);548 RTFileWrite(fh, pvDst, cbDst, NULL); 454 549 RTFileClose(fh); 455 550 #endif 456 551 } 457 552 458 RTCircBufReleaseWriteBlock(pCircBuf, cb Read);553 RTCircBufReleaseWriteBlock(pCircBuf, cbDst); 459 554 460 555 if (RT_FAILURE(rc)) 461 556 break; 462 557 463 Assert(cbLeft >= cb Read);464 cbLeft -= cb Read;465 466 cbWrittenTotal += cb Read;558 Assert(cbLeft >= cbDst); 559 cbLeft -= cbDst; 560 561 cbWrittenTotal += cbDst; 467 562 } 468 563 … … 548 643 } 549 644 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 DEBUG558 const uint64_t cMsElapsed = cTicksElapsed / (cTicksPerSec / 1000);559 #endif560 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 574 645 /** 575 646 * Transfers data of an HDA stream according to its usage (input / output). … … 583 654 * @returns IPRT status code. 584 655 * @param pStream HDA stream to update. 585 * @param cbToProcessMax Maximum of data (in bytes) to process.586 656 */ 587 657 int hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax) 588 658 { 589 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 590 AssertReturn(cbToProcessMax, VERR_INVALID_PARAMETER); 659 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 591 660 592 661 hdaStreamLock(pStream); … … 607 676 fProceed = false; 608 677 } 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)); 613 681 fProceed = false; 614 682 } … … 620 688 return VINF_SUCCESS; 621 689 } 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; 622 703 623 704 /* Sanity checks. */ … … 625 706 Assert(pStream->u64BDLBase); 626 707 Assert(pStream->u32CBL); 708 Assert(pStream->u16FIFOS); 627 709 628 710 /* State sanity checks. */ … … 637 719 } 638 720 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]; 654 733 while (cbLeft) 655 734 { 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 657 749 if (!cbChunk) 658 750 break; 659 751 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). */ 663 797 { 664 798 STAM_PROFILE_START(&pThis->StatOut, a); 665 799 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 668 832 LogRel(("HDA: Reading from stream #%RU8 DMA failed with %Rrc\n", pStream->u8SD, rc)); 669 833 670 834 STAM_PROFILE_STOP(&pThis->StatOut, a); 671 835 } 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 682 837 else /** @todo Handle duplex streams? */ 683 838 AssertFailed(); … … 692 847 Assert(pBDLE->State.u32BufOff <= pBDLE->Desc.u32BufSize); 693 848 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); 706 869 } 707 870 … … 710 873 Log3Func(("[SD%RU8] Complete: %R[bdle]\n", pStream->u8SD, pBDLE)); 711 874 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) 713 883 { 714 884 /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL register is set … … 716 886 */ 717 887 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 } 719 895 } 720 896 721 897 if (pStream->State.uCurBDLE == pStream->u16LVI) 722 898 { 723 Assert(pStream->u32CBL == HDA_STREAM_REG(pThis, LPIB, pStream->u8SD));724 725 899 pStream->State.uCurBDLE = 0; 726 hdaStreamUpdateLPIB(pStream, 0 /* LPIB */);727 900 } 728 901 else 729 902 pStream->State.uCurBDLE++; 730 903 904 /* Fetch the next BDLE entry. */ 731 905 hdaBDLEFetch(pThis, pBDLE, pStream->u64BDLBase, pStream->State.uCurBDLE); 732 733 Log3Func(("[SD%RU8] Fetching: %R[bdle]\n", pStream->u8SD, pBDLE));734 906 } 907 908 /* Do the position adjustment accounting. */ 909 pStream->State.cPosAdjustFramesLeft -= RT_MIN(pStream->State.cPosAdjustFramesLeft, cbDMA / HDA_FRAME_SIZE); 735 910 736 911 if (RT_FAILURE(rc)) … … 738 913 } 739 914 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. 745 968 * 746 969 * Note: This only must be done if the whole period is complete, and not if only … … 750 973 * 2) reads SDSTS (with BCIS set) and then 3) too early reads a (wrong) WALCLK value. 751 974 * 752 * snd_hda_intel on Linux will tell. */ 975 * snd_hda_intel on Linux will tell. 976 */ 753 977 HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_SDSTS_BCIS; 754 978 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. */ 768 981 #ifndef DEBUG 769 982 hdaProcessInterrupt(pThis); 770 983 #else 771 984 hdaProcessInterrupt(pThis, __FUNCTION__); 772 985 #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; 774 998 } 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)); 784 1025 785 1026 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 792 1027 hdaStreamUnlock(pStream); 793 1028 … … 862 1097 863 1098 /* 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. */ 865 1100 rc2 = AudioMixerSinkUpdate(pSink); 866 1101 AssertRC(rc2); … … 875 1110 if (fInTimer) 876 1111 { 877 rc2 = hdaStreamAsyncIONotify(pStream);878 AssertRC(rc2);879 }880 else881 {882 1112 #endif 883 1113 rc2 = AudioMixerSinkUpdate(pSink); … … 885 1115 886 1116 /* 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 913 1154 const uint32_t cbToTransfer = hdaStreamGetUsed(pStream); 914 1155 if (cbToTransfer) 915 1156 { 916 /* When running synchronously, do the DMA data transfers here.917 * Otherwise this will be done in the stream's async I/O thread. */918 1157 rc2 = hdaStreamTransfer(pStream, cbToTransfer); 919 1158 AssertRC(rc2); 920 1159 } 921 1160 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 922 } 1161 } /* fInTimer */ 923 1162 #endif 924 1163 } -
trunk/src/VBox/Devices/Audio/HDAStream.h
r69119 r69919 109 109 /** Circular buffer (FIFO) for holding DMA'ed data. */ 110 110 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; 114 138 /** The stream's period. Need for timing. */ 115 139 HDASTREAMPERIOD Period; … … 122 146 #endif 123 147 /** Unused, padding. */ 124 uint8_t Padding 1[3];148 uint8_t Padding3[3]; 125 149 } HDASTREAMSTATE, *PHDASTREAMSTATE; 126 150 … … 193 217 void hdaStreamReset(PHDASTATE pThis, PHDASTREAM pStream, uint8_t uSD); 194 218 int hdaStreamEnable(PHDASTREAM pStream, bool fEnable); 219 uint32_t hdaStreamGetPosition(PHDASTATE pThis, PHDASTREAM pStream); 220 void hdaStreamSetPosition(PHDASTREAM pStream, uint32_t u32LPIB); 221 uint32_t hdaStreamGetFree(PHDASTREAM pStream); 195 222 uint32_t hdaStreamGetUsed(PHDASTREAM pStream); 196 uint32_t hdaStreamGetFree(PHDASTREAM pStream); 223 bool hdaStreamTransferIsScheduled(PHDASTREAM pStream); 224 uint64_t hdaStreamTransferGetNext(PHDASTREAM pStream); 197 225 int hdaStreamTransfer(PHDASTREAM pStream, uint32_t cbToProcessMax); 198 uint32_t hdaStreamUpdateLPIB(PHDASTREAM pStream, uint32_t u32LPIB);199 226 void hdaStreamLock(PHDASTREAM pStream); 200 227 void hdaStreamUnlock(PHDASTREAM pStream); 201 228 int hdaStreamRead(PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead); 202 int hdaStreamWrite(PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten);229 int hdaStreamWrite(PHDASTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten); 203 230 void hdaStreamUpdate(PHDASTREAM pStream, bool fAsync); 204 231 # ifdef HDA_USE_DMA_ACCESS_HANDLER
Note:
See TracChangeset
for help on using the changeset viewer.