Changeset 88950 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- May 8, 2021 11:38:30 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144285
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
r88940 r88950 357 357 /** Circular buffer (FIFO) for holding DMA'ed data. */ 358 358 R3PTRTYPE(PRTCIRCBUF) pCircBuf; 359 /** Current circular buffer read offset (for tracing & logging). */ 360 uint64_t offRead; 361 /** Current circular buffer write offset (for tracing & logging). */ 362 uint64_t offWrite; 359 363 #if HC_ARCH_BITS == 32 360 364 uint32_t Padding; … … 362 366 /** The stream's current configuration. */ 363 367 PDMAUDIOSTREAMCFG Cfg; //+108 364 /** Asynchronous I/O state members. */365 AC97STREAMSTATEAIO AIO;366 368 /** Timestamp of the last DMA data transfer. */ 367 369 uint64_t tsTransferLast; … … 377 379 * Set in R3StreamInit(). */ 378 380 uint16_t uTimerHz; 379 uint8_t Padding3[2]; 381 /** Set if we've registered the asynchronous update job. */ 382 bool fRegisteredAsyncUpdateJob; 383 uint8_t Padding3; 380 384 /** (Virtual) clock ticks per transfer. */ 381 385 uint64_t cTransferTicks; 382 /** Timestamp (in ns) of last stream update. */386 /** Timestamp (in ns) of last stream update. */ 383 387 uint64_t tsLastUpdateNs; 388 389 /** Size of the DMA buffer (pCircBuf) in bytes. */ 390 uint32_t StatDmaBufSize; 391 /** Number of used bytes in the DMA buffer (pCircBuf). */ 392 uint32_t StatDmaBufUsed; 384 393 } AC97STREAMSTATE; 385 394 AssertCompileSizeAlignment(AC97STREAMSTATE, 8); … … 685 694 static int ichac97R3StreamTransfer(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, 686 695 PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax); 687 static void ichac97R3StreamUpdate(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC, PAC97STREAM pStream, 688 PAC97STREAMR3 pStreamCC, bool fInTimer); 696 static DECLCALLBACK(void) ichac97R3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser); 689 697 690 698 static DECLCALLBACK(void) ichac97R3Reset(PPDMDEVINS pDevIns); … … 692 700 static void ichac97R3MixerRemoveDrvStreams(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, PAUDMIXSINK pMixSink, 693 701 PDMAUDIODIR enmDir, PDMAUDIODSTSRCUNION dstSrc); 694 695 static int ichac97R3StreamAsyncIOCreate(PAC97STATE pThis, PAC97STATER3 pThisCC, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC);696 static int ichac97R3StreamAsyncIODestroy(PAC97STATE pThis, PAC97STREAMR3 pStreamCC);697 static void ichac97R3StreamAsyncIOLock(PAC97STREAMR3 pStreamCC);698 static void ichac97R3StreamAsyncIOUnlock(PAC97STREAMR3 pStreamCC);699 /*static void ichac97R3StreamAsyncIOEnable(PAC97STREAM pStream, bool fEnable); Unused */700 702 701 703 DECLINLINE(PDMAUDIODIR) ichac97GetDirFromSD(uint8_t uSD); … … 973 975 { 974 976 ichac97R3StreamLock(pStreamCC); 977 PAUDMIXSINK const pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD); 978 AudioMixerSinkLock(pSink); 975 979 976 980 int rc = VINF_SUCCESS; 977 981 if (fEnable) 978 rc = ichac97R3StreamAsyncIOCreate(pThis, pThisCC, pStream, pStreamCC); 979 if (RT_SUCCESS(rc)) 980 { 981 ichac97R3StreamAsyncIOLock(pStreamCC); 982 if (fEnable) 982 { 983 if (pStreamCC->State.pCircBuf) 984 RTCircBufReset(pStreamCC->State.pCircBuf); 985 986 rc = ichac97R3StreamOpen(pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fForce */); 987 988 /* Re-register the update job with the AIO thread with correct sched hint. 989 Note! We do not unregister it on disable because of draining. */ 990 if (pStreamCC->State.fRegisteredAsyncUpdateJob) 991 AudioMixerSinkRemoveUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC); 992 int rc2 = AudioMixerSinkAddUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC, 993 pStreamCC->State.Cfg.Device.cMsSchedulingHint); 994 AssertRC(rc2); 995 pStreamCC->State.fRegisteredAsyncUpdateJob = RT_SUCCESS(rc2) || rc2 == VERR_ALREADY_EXISTS; 996 997 /* Open debug files: */ 998 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled)) 999 { /* likely */ } 1000 else 983 1001 { 984 if (pStreamCC->State.pCircBuf) 985 RTCircBufReset(pStreamCC->State.pCircBuf); 986 987 rc = ichac97R3StreamOpen(pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fForce */); 988 989 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled)) 990 { /* likely */ } 991 else 1002 if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileStream)) 992 1003 { 993 if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileStream)) 994 { 995 int rc2 = AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileStream, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS, 996 &pStreamCC->State.Cfg.Props); 997 AssertRC(rc2); 998 } 999 1000 if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileDMA)) 1001 { 1002 int rc2 = AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileDMA, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS, 1003 &pStreamCC->State.Cfg.Props); 1004 AssertRC(rc2); 1005 } 1004 rc2 = AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileStream, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS, 1005 &pStreamCC->State.Cfg.Props); 1006 AssertRC(rc2); 1007 } 1008 1009 if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileDMA)) 1010 { 1011 rc2 = AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileDMA, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS, 1012 &pStreamCC->State.Cfg.Props); 1013 AssertRC(rc2); 1006 1014 } 1007 1015 } 1008 else 1009 rc = ichac97R3StreamClose(pStream); 1010 1011 if (RT_SUCCESS(rc)) 1012 { 1013 /* First, enable or disable the stream and the stream's sink, if any. */ 1014 rc = AudioMixerSinkEnable(ichac97R3IndexToSink(pThisCC, pStream->u8SD), fEnable); 1015 } 1016 1017 ichac97R3StreamAsyncIOUnlock(pStreamCC); 1016 } 1017 else 1018 rc = ichac97R3StreamClose(pStream); 1019 1020 if (RT_SUCCESS(rc)) 1021 { 1022 /* First, enable or disable the stream and the stream's sink, if any. */ 1023 rc = AudioMixerSinkEnable(pSink, fEnable); 1018 1024 } 1019 1025 1020 1026 /* Make sure to leave the lock before (eventually) starting the timer. */ 1027 AudioMixerSinkUnlock(pSink); 1021 1028 ichac97R3StreamUnlock(pStreamCC); 1022 1029 LogFunc(("[SD%RU8] fEnable=%RTbool, rc=%Rrc\n", pStream->u8SD, fEnable, rc)); … … 1120 1127 * 1121 1128 * @returns VBox status code. 1122 * @param pThis The sharedAC'97 state.1129 * @param pThisCC The ring-3 AC'97 state. 1123 1130 * @param pStream The AC'97 stream to destroy (shared). 1124 1131 * @param pStreamCC The AC'97 stream to destroy (ring-3). 1125 1132 */ 1126 static void ichac97R3StreamDestroy(PAC97STATE pThis, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)1133 static void ichac97R3StreamDestroy(PAC97STATER3 pThisCC, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC) 1127 1134 { 1128 1135 LogFlowFunc(("[SD%RU8]\n", pStream->u8SD)); … … 1133 1140 AssertRC(rc2); 1134 1141 1135 rc2 = ichac97R3StreamAsyncIODestroy(pThis, pStreamCC); 1136 AssertRC(rc2); 1142 if (pStreamCC->State.fRegisteredAsyncUpdateJob) 1143 { 1144 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD); 1145 if (pSink) 1146 AudioMixerSinkRemoveUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC); 1147 pStreamCC->State.fRegisteredAsyncUpdateJob = false; 1148 } 1137 1149 1138 1150 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled)) … … 1171 1183 */ 1172 1184 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++) 1173 ichac97R3StreamDestroy(pThis , &pThis->aStreams[i], &pThisCC->aStreams[i]);1185 ichac97R3StreamDestroy(pThisCC, &pThis->aStreams[i], &pThisCC->aStreams[i]); 1174 1186 1175 1187 /* 1176 1188 * Destroy all sinks. 1177 1189 */ 1178 1179 PDMAUDIODSTSRCUNION dstSrc; 1190 PDMAUDIODSTSRCUNION dstSrc; /** @todo r=bird: this is just impractical. combine the two enums into one, they already have no overlapping values. */ 1180 1191 if (pThisCC->pSinkLineIn) 1181 1192 { … … 1206 1217 } 1207 1218 1208 /** 1209 * Writes audio data from a mixer sink into an AC'97 stream's DMA buffer. 1210 * 1211 * @returns VBox status code. 1212 * @param pDstStreamCC The AC'97 stream to write to (ring-3). 1213 * @param pSrcMixSink Mixer sink to get audio data to write from. 1214 * @param cbToWrite Number of bytes to write. 1215 * @param pcbWritten Number of bytes written. Optional. 1216 */ 1217 static int ichac97R3StreamWrite(PAC97STREAMR3 pDstStreamCC, PAUDMIXSINK pSrcMixSink, uint32_t cbToWrite, uint32_t *pcbWritten) 1218 { 1219 AssertPtrReturn(pSrcMixSink, VERR_INVALID_POINTER); 1220 AssertReturn(cbToWrite > 0, VERR_INVALID_PARAMETER); 1221 /* pcbWritten is optional. */ 1222 1223 PRTCIRCBUF pCircBuf = pDstStreamCC->State.pCircBuf; 1224 AssertPtr(pCircBuf); 1225 1226 uint32_t cbRead = 0; 1227 1228 void *pvDst; 1229 size_t cbDst; 1230 RTCircBufAcquireWriteBlock(pCircBuf, cbToWrite, &pvDst, &cbDst); 1231 1232 if (cbDst) 1233 { 1234 int rc2 = AudioMixerSinkRead(pSrcMixSink, AUDMIXOP_COPY, pvDst, (uint32_t)cbDst, &cbRead); 1235 AssertRC(rc2); 1236 1237 if (RT_LIKELY(!pDstStreamCC->Dbg.Runtime.fEnabled)) 1238 { /* likely */ } 1239 else 1240 AudioHlpFileWrite(pDstStreamCC->Dbg.Runtime.pFileStream, pvDst, cbRead, 0 /* fFlags */); 1241 } 1242 1243 RTCircBufReleaseWriteBlock(pCircBuf, cbRead); 1244 1245 if (pcbWritten) 1246 *pcbWritten = cbRead; 1247 1248 return VINF_SUCCESS; 1249 } 1250 1251 /** 1252 * Reads audio data from an AC'97 stream's DMA buffer and writes into a specified mixer sink. 1253 * 1254 * @returns VBox status code. 1255 * @param pSrcStreamCC AC'97 stream to read audio data from (ring-3). 1256 * @param pDstMixSink Mixer sink to write audio data to. 1257 * @param cbToRead Number of bytes to read. 1258 * @param pcbRead Number of bytes read. Optional. 1259 */ 1260 static int ichac97R3StreamRead(PAC97STREAMR3 pSrcStreamCC, PAUDMIXSINK pDstMixSink, uint32_t cbToRead, uint32_t *pcbRead) 1261 { 1262 AssertPtrReturn(pDstMixSink, VERR_INVALID_POINTER); 1263 AssertReturn(cbToRead > 0, VERR_INVALID_PARAMETER); 1264 /* pcbRead is optional. */ 1265 1266 PRTCIRCBUF pCircBuf = pSrcStreamCC->State.pCircBuf; 1267 AssertPtr(pCircBuf); 1268 1269 void *pvSrc; 1270 size_t cbSrc; 1271 1272 int rc = VINF_SUCCESS; 1273 1274 uint32_t cbReadTotal = 0; 1275 uint32_t cbLeft = RT_MIN(cbToRead, (uint32_t)RTCircBufUsed(pCircBuf)); 1276 1277 while (cbLeft) 1278 { 1279 uint32_t cbWritten = 0; 1280 1281 RTCircBufAcquireReadBlock(pCircBuf, cbLeft, &pvSrc, &cbSrc); 1282 1283 if (cbSrc) 1284 { 1285 if (RT_LIKELY(!pSrcStreamCC->Dbg.Runtime.fEnabled)) 1286 { /* likely */ } 1287 else 1288 AudioHlpFileWrite(pSrcStreamCC->Dbg.Runtime.pFileStream, pvSrc, cbSrc, 0 /* fFlags */); 1289 1290 rc = AudioMixerSinkWrite(pDstMixSink, AUDMIXOP_COPY, pvSrc, (uint32_t)cbSrc, &cbWritten); 1291 AssertRC(rc); 1292 1293 Assert(cbSrc >= cbWritten); 1294 Log3Func(("[SD%RU8] %RU32/%zu bytes read\n", pSrcStreamCC->u8SD, cbWritten, cbSrc)); 1295 } 1296 1297 RTCircBufReleaseReadBlock(pCircBuf, cbWritten); 1298 1299 if ( !cbWritten /* Nothing written? */ 1300 || RT_FAILURE(rc)) 1301 break; 1302 1303 Assert(cbLeft >= cbWritten); 1304 cbLeft -= cbWritten; 1305 1306 cbReadTotal += cbWritten; 1307 } 1308 1309 if (pcbRead) 1310 *pcbRead = cbReadTotal; 1311 1312 return rc; 1313 } 1314 1315 1316 /** 1317 * Asynchronous I/O thread for an AC'97 stream. 1318 * This will do the heavy lifting work for us as soon as it's getting notified by another thread. 1319 * 1320 * @returns VBox status code. 1321 * @param hThreadSelf Thread handle. 1322 * @param pvUser User argument. Must be of type PAC97STREAMTHREADCTX. 1323 */ 1324 static DECLCALLBACK(int) ichac97R3StreamAsyncIOThread(RTTHREAD hThreadSelf, void *pvUser) 1325 { 1326 PAC97STREAMTHREADCTX pCtx = (PAC97STREAMTHREADCTX)pvUser; 1327 PAC97STATE pThis = pCtx->pThis; 1328 PAC97STATER3 pThisCC = pCtx->pThisCC; 1329 PAC97STREAM pStream = pCtx->pStream; 1330 PAC97STREAMR3 pStreamCC = pCtx->pStreamCC; 1331 PAC97STREAMSTATEAIO pAIO = &pStreamCC->State.AIO; 1332 1333 ASMAtomicXchgBool(&pAIO->fStarted, true); 1334 1335 RTThreadUserSignal(hThreadSelf); 1336 1337 LogFunc(("[SD%RU8] Started\n", pStream->u8SD)); 1338 1339 for (;;) 1340 { 1341 Log2Func(("[SD%RU8] Waiting ...\n", pStream->u8SD)); 1342 1343 int rc2 = RTSemEventWait(pAIO->Event, RT_INDEFINITE_WAIT); 1344 if (RT_FAILURE(rc2)) 1345 break; 1346 1347 if (ASMAtomicReadBool(&pAIO->fShutdown)) 1348 break; 1349 1350 rc2 = RTCritSectEnter(&pAIO->CritSect); 1351 if (RT_SUCCESS(rc2)) 1352 { 1353 if (!pAIO->fEnabled) 1354 { 1355 RTCritSectLeave(&pAIO->CritSect); 1356 continue; 1357 } 1358 1359 ichac97R3StreamUpdate(pThisCC->pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fInTimer */); 1360 1361 int rc3 = RTCritSectLeave(&pAIO->CritSect); 1362 AssertRC(rc3); 1363 } 1364 1365 AssertRC(rc2); 1366 } 1367 1368 LogFunc(("[SD%RU8] Ended\n", pStream->u8SD)); 1369 1370 ASMAtomicXchgBool(&pAIO->fStarted, false); 1371 1372 RTMemFree(pCtx); 1373 pCtx = NULL; 1374 1375 return VINF_SUCCESS; 1376 } 1377 1378 /** 1379 * Creates the async I/O thread for a specific AC'97 audio stream. 1380 * 1381 * @returns VBox status code. 1382 * @param pThis The shared AC'97 state (shared). 1383 * @param pThisCC The shared AC'97 state (ring-3). 1384 * @param pStream AC'97 audio stream to create the async I/O thread for (shared). 1385 * @param pStreamCC AC'97 audio stream to create the async I/O thread for (ring-3). 1386 */ 1387 static int ichac97R3StreamAsyncIOCreate(PAC97STATE pThis, PAC97STATER3 pThisCC, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC) 1388 { 1389 PAC97STREAMSTATEAIO pAIO = &pStreamCC->State.AIO; 1390 1391 int rc; 1392 1393 if (!ASMAtomicReadBool(&pAIO->fStarted)) 1394 { 1395 pAIO->fShutdown = false; 1396 pAIO->fEnabled = true; /* Enabled by default. */ 1397 1398 rc = RTSemEventCreate(&pAIO->Event); 1399 if (RT_SUCCESS(rc)) 1400 { 1401 rc = RTCritSectInit(&pAIO->CritSect); 1402 if (RT_SUCCESS(rc)) 1403 { 1404 /** @todo r=bird: 1405 * Why aren't this code using the PDM threads (PDMDevHlpThreadCreate)? 1406 * They would help you with managing stuff like VM suspending, resuming 1407 * and powering off. 1408 * 1409 * Finally, just create the threads at construction time. */ 1410 PAC97STREAMTHREADCTX pCtx = (PAC97STREAMTHREADCTX)RTMemAllocZ(sizeof(AC97STREAMTHREADCTX)); 1411 if (pCtx) 1412 { 1413 pCtx->pStream = pStream; 1414 pCtx->pStreamCC = pStreamCC; 1415 pCtx->pThis = pThis; 1416 pCtx->pThisCC = pThisCC; 1417 1418 rc = RTThreadCreateF(&pAIO->Thread, ichac97R3StreamAsyncIOThread, pCtx, 0 /*cbStack*/, RTTHREADTYPE_IO, 1419 RTTHREADFLAGS_WAITABLE | RTTHREADFLAGS_COM_MTA, "ac97AIO%RU8", pStreamCC->u8SD); 1420 if (RT_SUCCESS(rc)) 1421 rc = RTThreadUserWait(pAIO->Thread, 30 * 1000 /* 30s timeout */); 1422 } 1423 else 1424 rc = VERR_NO_MEMORY; 1425 } 1426 } 1427 } 1428 else 1429 rc = VINF_SUCCESS; 1430 1431 LogFunc(("[SD%RU8] Returning %Rrc\n", pStreamCC->u8SD, rc)); 1432 return rc; 1433 } 1434 1435 /** 1436 * Lets the stream's async I/O thread know that there is some data to process. 1437 * 1438 * @returns VBox status code. 1439 * @param pStreamCC The AC'97 stream to notify async I/O thread 1440 * for (ring-3). 1441 */ 1442 static int ichac97R3StreamAsyncIONotify(PAC97STREAMR3 pStreamCC) 1443 { 1444 LogFunc(("[SD%RU8]\n", pStreamCC->u8SD)); 1445 return RTSemEventSignal(pStreamCC->State.AIO.Event); 1446 } 1447 1448 /** 1449 * Destroys the async I/O thread of a specific AC'97 audio stream. 1450 * 1451 * @returns VBox status code. 1452 * @param pThis The shared AC'97 state. 1453 * @param pStreamR3 AC'97 audio stream to destroy the async I/O thread for. 1454 */ 1455 static int ichac97R3StreamAsyncIODestroy(PAC97STATE pThis, PAC97STREAMR3 pStreamR3) 1456 { 1457 RT_NOREF(pThis); 1458 1459 PAC97STREAMSTATEAIO pAIO = &pStreamR3->State.AIO; 1460 1461 if (!ASMAtomicReadBool(&pAIO->fStarted)) 1462 return VINF_SUCCESS; 1463 1464 ASMAtomicWriteBool(&pAIO->fShutdown, true); 1465 1466 int rc = ichac97R3StreamAsyncIONotify(pStreamR3); 1467 AssertRC(rc); 1468 1469 int rcThread; 1470 rc = RTThreadWait(pAIO->Thread, 30 * 1000 /* 30s timeout */, &rcThread); 1471 LogFunc(("Async I/O thread ended with %Rrc (%Rrc)\n", rc, rcThread)); 1472 1473 if (RT_SUCCESS(rc)) 1474 { 1475 rc = RTCritSectDelete(&pAIO->CritSect); 1476 AssertRC(rc); 1477 1478 rc = RTSemEventDestroy(pAIO->Event); 1479 AssertRC(rc); 1480 1481 pAIO->fStarted = false; 1482 pAIO->fShutdown = false; 1483 pAIO->fEnabled = false; 1484 } 1485 1486 LogFunc(("[SD%RU8] Returning %Rrc\n", pStreamR3->u8SD, rc)); 1487 return rc; 1488 } 1489 1490 /** 1491 * Locks the async I/O thread of a specific AC'97 audio stream. 1492 * 1493 * @param pStreamCC AC'97 stream to lock async I/O thread for. 1494 */ 1495 static void ichac97R3StreamAsyncIOLock(PAC97STREAMR3 pStreamCC) 1496 { 1497 PAC97STREAMSTATEAIO pAIO = &pStreamCC->State.AIO; 1498 1499 if (!ASMAtomicReadBool(&pAIO->fStarted)) 1500 return; 1501 1502 int rc2 = RTCritSectEnter(&pAIO->CritSect); 1503 AssertRC(rc2); 1504 } 1505 1506 /** 1507 * Unlocks the async I/O thread of a specific AC'97 audio stream. 1508 * 1509 * @param pStreamCC AC'97 stream to unlock async I/O thread for. 1510 */ 1511 static void ichac97R3StreamAsyncIOUnlock(PAC97STREAMR3 pStreamCC) 1512 { 1513 PAC97STREAMSTATEAIO pAIO = &pStreamCC->State.AIO; 1514 1515 if (!ASMAtomicReadBool(&pAIO->fStarted)) 1516 return; 1517 1518 int rc2 = RTCritSectLeave(&pAIO->CritSect); 1519 AssertRC(rc2); 1520 } 1521 1522 #if 0 /* Unused */ 1523 /** 1524 * Enables (resumes) or disables (pauses) the async I/O thread. 1525 * 1526 * @param pStream AC'97 stream to enable/disable async I/O thread for. 1527 * @param fEnable Whether to enable or disable the I/O thread. 1528 * 1529 * @remarks Does not do locking. 1530 */ 1531 static void ichac97R3StreamAsyncIOEnable(PAC97STREAM pStream, bool fEnable) 1532 { 1533 PAC97STREAMSTATEAIO pAIO = &pStreamCC->State.AIO; 1534 ASMAtomicXchgBool(&pAIO->fEnabled, fEnable); 1535 } 1219 1220 /** 1221 * Input streams: Pulls data from the mixer, putting it in the internal DMA 1222 * buffer. 1223 * 1224 * @param pStreamR3 HDA stream to update (ring-3 bits). 1225 * @param pSink The mixer sink to pull from. 1226 */ 1227 static void ichac97R3StreamPullFromMixer(PAC97STREAMR3 pStreamR3, PAUDMIXSINK pSink) 1228 { 1229 #ifdef LOG_ENABLED 1230 uint64_t const offWriteOld = pStreamR3->State.offWrite; 1536 1231 #endif 1232 pStreamR3->State.offWrite = AudioMixerSinkTransferFromCircBuf(pSink, 1233 pStreamR3->State.pCircBuf, 1234 pStreamR3->State.offWrite, 1235 pStreamR3->u8SD, 1236 pStreamR3->Dbg.Runtime.fEnabled 1237 ? pStreamR3->Dbg.Runtime.pFileStream : NULL); 1238 1239 Log3Func(("[SD%RU8] transferred=%#RX64 bytes -> @%#RX64\n", pStreamR3->u8SD, 1240 pStreamR3->State.offWrite - offWriteOld, pStreamR3->State.offWrite)); 1241 1242 /* Update buffer stats. */ 1243 pStreamR3->State.StatDmaBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf); 1244 } 1245 1246 1247 /** 1248 * Output streams: Pushes data to the mixer. 1249 * 1250 * @param pStreamR3 HDA stream to update (ring-3 bits). 1251 * @param pSink The mixer sink to push to. 1252 */ 1253 static void ichac97R3StreamPushToMixer(PAC97STREAMR3 pStreamR3, PAUDMIXSINK pSink) 1254 { 1255 #ifdef LOG_ENABLED 1256 uint64_t const offReadOld = pStreamR3->State.offRead; 1257 #endif 1258 pStreamR3->State.offRead = AudioMixerSinkTransferFromCircBuf(pSink, 1259 pStreamR3->State.pCircBuf, 1260 pStreamR3->State.offRead, 1261 pStreamR3->u8SD, 1262 pStreamR3->Dbg.Runtime.fEnabled 1263 ? pStreamR3->Dbg.Runtime.pFileStream : NULL); 1264 1265 Log3Func(("[SD%RU8] transferred=%#RX64 bytes -> @%#RX64\n", pStreamR3->u8SD, 1266 pStreamR3->State.offRead - offReadOld, pStreamR3->State.offRead)); 1267 1268 /* Update buffer stats. */ 1269 pStreamR3->State.StatDmaBufUsed = (uint32_t)RTCircBufUsed(pStreamR3->State.pCircBuf); 1270 } 1271 1537 1272 1538 1273 # ifdef LOG_ENABLED … … 1570 1305 1571 1306 /** 1572 * Updates an AC'97 stream by doing its required data transfers. 1573 * The host sink(s) set the overall pace. 1574 * 1575 * This routine is called by both, the synchronous and the asynchronous 1576 * implementations. 1577 * 1578 * When running synchronously, the device DMA transfers *and* the mixer sink 1579 * processing is within the device timer. 1580 * 1581 * When running asynchronously, only the device DMA transfers are done in the 1582 * device timer, whereas the mixer sink processing then is done in the stream's 1583 * own async I/O thread. This thread also will call this function 1584 * (with fInTimer set to @c false). 1307 * Updates an AC'97 stream by doing its DMA transfers. 1308 * 1309 * The host sink(s) set the overall pace (bird: no it doesn't, the DMA timer 1310 * does - we just hope like heck it matches the speed at which the *backend* 1311 * host audio driver processes samples). 1585 1312 * 1586 1313 * @param pDevIns The device instance. … … 1589 1316 * @param pStream The AC'97 stream to update (shared). 1590 1317 * @param pStreamCC The AC'97 stream to update (ring-3). 1591 * @param fInTimer Whether to this function was called from the timer 1592 * context or an asynchronous I/O stream thread (if supported). 1593 */ 1594 static void ichac97R3StreamUpdate(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC, 1595 PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, bool fInTimer) 1596 { 1597 RT_NOREF(fInTimer); 1598 1318 */ 1319 static void ichac97R3StreamUpdateDma(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC, 1320 PAC97STREAM pStream, PAC97STREAMR3 pStreamCC) 1321 { 1322 int rc2; 1599 1323 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD); 1600 1324 AssertPtr(pSink); 1601 1602 if (!AudioMixerSinkIsActive(pSink)) /* No sink available? Bail out. */ 1603 return; 1604 1605 int rc2; 1606 1607 if (pStreamCC->State.Cfg.enmDir == PDMAUDIODIR_OUT) /* Output (SDO). */ 1608 { 1609 if (fInTimer) 1325 if (AudioMixerSinkIsActive(pSink)) 1326 { 1327 if (pStreamCC->State.Cfg.enmDir == PDMAUDIODIR_OUT) /* Output (SDO). */ 1610 1328 { 1611 const uint32_t cbStreamFree = ichac97R3StreamGetFree(pStreamCC); 1329 uint32_t cbStreamFree = ichac97R3StreamGetFree(pStreamCC); 1330 if (cbStreamFree) 1331 { /* likely */ } 1332 else 1333 { 1334 /** @todo Record this as a statistic. Try make some space available. */ 1335 } 1612 1336 if (cbStreamFree) 1613 1337 { … … 1625 1349 pStreamCC->State.tsLastUpdateNs = RTTimeNanoTS(); 1626 1350 } 1351 1352 rc2 = AudioMixerSinkSignalUpdateJob(pSink); 1353 AssertRC(rc2); 1627 1354 } 1628 1629 Log3Func(("[SD%RU8] fInTimer=%RTbool\n", pStream->u8SD, fInTimer)); 1630 1631 rc2 = ichac97R3StreamAsyncIONotify(pStreamCC); 1632 AssertRC(rc2); 1633 1634 if (!fInTimer) /* In async I/O thread */ 1355 else /* Input (SDI). */ 1635 1356 { 1636 const uint32_t cbSinkWritable = AudioMixerSinkGetWritable(pSink); 1637 const uint32_t cbStreamReadable = ichac97R3StreamGetUsed(pStreamCC); 1638 const uint32_t cbToReadFromStream = RT_MIN(cbStreamReadable, cbSinkWritable); 1639 1640 Log3Func(("[SD%RU8] cbSinkWritable=%RU32, cbStreamReadable=%RU32\n", pStream->u8SD, cbSinkWritable, cbStreamReadable)); 1641 1642 if (cbToReadFromStream) 1643 { 1644 /* Read (guest output) data and write it to the stream's sink. */ 1645 rc2 = ichac97R3StreamRead(pStreamCC, pSink, cbToReadFromStream, NULL /* pcbRead */); 1646 AssertRC(rc2); 1647 } 1648 } 1649 /* When running synchronously, update the associated sink here. 1650 * Otherwise this will be done in the async I/O thread. */ 1651 rc2 = AudioMixerSinkUpdate(pSink); 1652 AssertRC(rc2); 1653 } 1654 else /* Input (SDI). */ 1655 { 1656 if (!fInTimer) 1657 { 1658 rc2 = AudioMixerSinkUpdate(pSink); 1659 AssertRC(rc2); 1660 1661 /* Is the sink ready to be read (host input data) from? If so, by how much? */ 1662 uint32_t cbSinkReadable = AudioMixerSinkGetReadable(pSink); 1663 1664 /* How much (guest input) data is available for writing at the moment for the AC'97 stream? */ 1665 uint32_t cbStreamFree = ichac97R3StreamGetFree(pStreamCC); 1666 1667 Log3Func(("[SD%RU8] cbSinkReadable=%RU32, cbStreamFree=%RU32\n", pStream->u8SD, cbSinkReadable, cbStreamFree)); 1668 1669 /* Do not read more than the sink can provide at the moment. 1670 * The host sets the overall pace. */ 1671 if (cbSinkReadable > cbStreamFree) 1672 cbSinkReadable = cbStreamFree; 1673 1674 if (cbSinkReadable) 1675 { 1676 /* Write (guest input) data to the stream which was read from stream's sink before. */ 1677 rc2 = ichac97R3StreamWrite(pStreamCC, pSink, cbSinkReadable, NULL /* pcbWritten */); 1678 AssertRC(rc2); 1679 } 1680 } 1681 else /* fInTimer */ 1682 { 1683 1357 #if 0 /* bird: I just love when crusial code like this with no explanation. This just causing AIO 1358 * skipping a DMA timer cycle if the timer callback is a bit quicker than the 'hint' (see HDA/9890). */ 1684 1359 const uint64_t tsNowNs = RTTimeNanoTS(); 1685 1360 if (tsNowNs - pStreamCC->State.tsLastUpdateNs >= pStreamCC->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS) 1686 1361 { 1687 rc2 = ichac97R3StreamAsyncIONotify(pStreamCC);1362 rc2 = AudioMixerSinkSignalUpdateJob(pSink); 1688 1363 AssertRC(rc2); 1689 1364 1690 1365 pStreamCC->State.tsLastUpdateNs = tsNowNs; 1691 1366 } 1692 1693 const uint32_t cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC); 1367 #endif 1368 1369 uint32_t cbStreamUsed = ichac97R3StreamGetUsed(pStreamCC); 1370 if (cbStreamUsed) 1371 { /* likey */ } 1372 else 1373 { 1374 /** @todo Record this as a statistic. Try pull some data into the DMA buffer.*/ 1375 } 1376 1694 1377 if (cbStreamUsed) 1695 1378 { … … 1699 1382 AssertRC(rc2); 1700 1383 } 1384 1385 /* 1386 * We should always kick the AIO thread. 1387 */ 1388 /** @todo This isn't entirely ideal. If we get into an underrun situation, 1389 * we ideally want the AIO thread to run right before the DMA timer 1390 * rather than right after it ran. */ 1391 Log5Func(("Notifying AIO thread\n")); 1392 rc2 = AudioMixerSinkSignalUpdateJob(pSink); 1393 AssertRC(rc2); 1394 pStreamCC->State.tsLastUpdateNs = RTTimeNanoTS(); 1701 1395 } 1702 1396 } 1397 } 1398 1399 1400 /** 1401 * @callback_method_impl{FNRTTHREAD, Asynchronous I/O thread for an AC'97 stream.} 1402 * 1403 * For output streams this moves data from the internal DMA buffer (in which 1404 * ichac97R3StreamUpdateDma put it), thru the mixer and to the various backend 1405 * audio devices. 1406 * 1407 * For input streams this pulls data from the backend audio device(s), thru the 1408 * mixer and puts it in the internal DMA buffer ready for 1409 * ichac97R3StreamUpdateDma to pump into guest memory. 1410 */ 1411 static DECLCALLBACK(void) ichac97R3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser) 1412 { 1413 PAC97STATER3 const pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3); 1414 PAC97STREAMR3 const pStreamCC = (PAC97STREAMR3)pvUser; 1415 uintptr_t const idxStream = pStreamCC - &pThisCC->aStreams[0]; 1416 Assert(pStreamCC->u8SD == idxStream); 1417 Assert(pSink == ichac97R3IndexToSink(pThisCC, (uint8_t)idxStream)); 1418 1419 /* 1420 * Output (SDO). 1421 */ 1422 if (pStreamCC->State.Cfg.enmDir == PDMAUDIODIR_OUT) 1423 ichac97R3StreamPushToMixer(pStreamCC, pSink); 1424 /* 1425 * Input (SDI). 1426 */ 1427 else 1428 ichac97R3StreamPullFromMixer(pStreamCC, pSink); 1703 1429 } 1704 1430 … … 2187 1913 if (RT_SUCCESS(rc)) 2188 1914 { 1915 pStreamCC->State.StatDmaBufSize = (uint32_t)RTCircBufSize(pStreamCC->State.pCircBuf); 1916 2189 1917 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pMixSink, Cfg.enmDir, Cfg.u); 2190 2191 1918 rc = ichac97R3MixerAddDrvStreams(pDevIns, pThisCC, pMixSink, &Cfg); 2192 1919 if (RT_SUCCESS(rc)) … … 2720 2447 Assert(PDMDevHlpTimerIsLockOwner(pDevIns, pStream->hTimer)); 2721 2448 2722 ichac97R3StreamUpdate (pDevIns, pThis, pThisCC, pStream, pStreamCC, true /* fInTimer */);2449 ichac97R3StreamUpdateDma(pDevIns, pThis, pThisCC, pStream, pStreamCC); 2723 2450 2724 2451 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD);
Note:
See TracChangeset
for help on using the changeset viewer.