Changeset 76179 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Dec 12, 2018 2:51:09 PM (6 years ago)
- svn:sync-xref-src-repo-rev:
- 127434
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
r76158 r76179 51 51 52 52 /** Default timer frequency (in Hz). */ 53 #define AC97_TIMER_HZ_DEFAULT 200 53 #define AC97_TIMER_HZ_DEFAULT 100 54 55 /** Maximum number of streams we support. */ 56 #define AC97_MAX_STREAMS 3 54 57 55 58 /** Maximum FIFO size (in bytes). */ … … 219 222 220 223 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 224 /** 225 * Enumeration of AC'97 source indices. 226 * 227 * Note: The order of this indices is fixed (also applies for saved states) for the moment. 228 * So make sure you know what you're done when altering this. 229 */ 221 230 typedef enum 222 231 { … … 256 265 uint32_t addr; 257 266 uint32_t ctl_len; 258 } AC97BDLE, *PAC97BDLE; 267 } AC97BDLE; 268 AssertCompileSize(AC97BDLE, 8); 269 /** Pointer to BDLE. */ 270 typedef AC97BDLE *PAC97BDLE; 259 271 260 272 /** … … 299 311 #endif 300 312 313 /** The ICH AC'97 (Intel) controller. */ 314 typedef struct AC97STATE *PAC97STATE; 315 301 316 /** 302 317 * Structure for keeping the internal state of an AC'97 stream. … … 318 333 AC97STREAMSTATEAIO AIO; 319 334 #endif 320 /** Timestamp (in ns) of last DMA transfer. 321 * For output streams this is the last DMA read, 322 * for input streams this is the last DMA write. */ 323 uint64_t tsLastTransferNs; 324 /** Timestamp (in ns) of last DMA buffer read / write. */ 325 uint64_t tsLastReadWriteNs; 326 /** Timestamp (in ns) of last stream update. */ 335 /** Timestamp of the last DMA data transfer. */ 336 uint64_t tsTransferLast; 337 /** Timestamp of the next DMA data transfer. 338 * Next for determining the next scheduling window. 339 * Can be 0 if no next transfer is scheduled. */ 340 uint64_t tsTransferNext; 341 /** Total transfer size (in bytes) of a transfer period. */ 342 uint32_t cbTransferSize; 343 /** Transfer chunk size (in bytes) of a transfer period. */ 344 uint32_t cbTransferChunk; 345 /** How many bytes already have been processed in within 346 * the current transfer period. */ 347 uint32_t cbTransferProcessed; 348 /** The stream's timer Hz rate. 349 * This value can can be different from the device's default Hz rate, 350 * depending on the rate the stream expects (e.g. for 5.1 speaker setups). 351 * Set in R3StreamInit(). */ 352 uint16_t uTimerHz; 353 uint8_t Padding3[2]; 354 /** (Virtual) clock ticks per byte. */ 355 uint64_t cTicksPerByte; 356 /** (Virtual) clock ticks per transfer. */ 357 uint64_t cTransferTicks; 358 /** Timestamp (in ns) of last stream update. */ 327 359 uint64_t tsLastUpdateNs; 328 360 } AC97STREAMSTATE; … … 364 396 { 365 397 /** Stream number (SDn). */ 366 uint8_t u8SD;367 uint8_t abPadding[7];398 uint8_t u8SD; 399 uint8_t abPadding[7]; 368 400 /** Bus master registers of this stream. */ 369 AC97BMREGS Regs;401 AC97BMREGS Regs; 370 402 /** Internal state of this stream. */ 371 AC97STREAMSTATE State; 403 AC97STREAMSTATE State; 404 /** Pointer to parent (AC'97 state). */ 405 R3PTRTYPE(PAC97STATE) pAC97State; 372 406 /** Debug information. */ 373 AC97STREAMDBGINFO Dbg;407 AC97STREAMDBGINFO Dbg; 374 408 } AC97STREAM, *PAC97STREAM; 375 409 AssertCompileSizeAlignment(AC97STREAM, 8); … … 464 498 uint32_t last_samp; 465 499 uint8_t mixer_data[256]; 466 /** AC'97 stream for line-in. */ 467 AC97STREAM StreamLineIn; 468 /** AC'97 stream for microphone-in. */ 469 AC97STREAM StreamMicIn; 470 /** AC'97 stream for output. */ 471 AC97STREAM StreamOut; 472 /** Number of active (running) SDn streams. */ 473 uint8_t cStreamsActive; 474 /** Flag indicating whether the timer is active or not. */ 475 bool fTimerActive; 500 /** Array of AC'97 streams. */ 501 AC97STREAM aStreams[AC97_MAX_STREAMS]; 476 502 /** The device timer Hz rate. Defaults to AC97_TIMER_HZ_DEFAULT_DEFAULT. */ 477 503 uint16_t uTimerHz; 478 504 /** The timer for pumping data thru the attached LUN drivers - RCPtr. */ 479 PTMTIMERRC pTimerRC ;505 PTMTIMERRC pTimerRC[AC97_MAX_STREAMS]; 480 506 /** The timer for pumping data thru the attached LUN drivers - R3Ptr. */ 481 PTMTIMERR3 pTimerR3 ;507 PTMTIMERR3 pTimerR3[AC97_MAX_STREAMS]; 482 508 /** The timer for pumping data thru the attached LUN drivers - R0Ptr. */ 483 PTMTIMERR0 pTimerR0; 484 /** The timer interval for pumping data thru the LUN drivers in timer ticks. */ 485 uint64_t cTimerTicks; 486 /** Timestamp of the last timer callback (ac97Timer). 487 * Used to calculate the time actually elapsed between two timer callbacks. */ 488 uint64_t uTimerTS; 509 PTMTIMERR0 pTimerR0[AC97_MAX_STREAMS]; 489 510 #ifdef VBOX_WITH_STATISTICS 490 511 STAMPROFILE StatTimer; … … 517 538 AC97STATEDBGINFO Dbg; 518 539 } AC97STATE; 519 AssertCompileMemberAlignment(AC97STATE, StreamLineIn, 8);540 AssertCompileMemberAlignment(AC97STATE, aStreams, 8); 520 541 /** Pointer to a AC'97 state. */ 521 542 typedef AC97STATE *PAC97STATE; … … 556 577 } while (0) 557 578 579 #ifdef IN_RC 580 /** Retrieves an attribute from a specific audio stream in RC. */ 581 # define DEVAC97_CTX_SUFF_SD(a_Var, a_SD) a_Var##RC[a_SD] 582 #elif defined(IN_RING0) 583 /** Retrieves an attribute from a specific audio stream in R0. */ 584 # define DEVAC97_CTX_SUFF_SD(a_Var, a_SD) a_Var##R0[a_SD] 585 #else 586 /** Retrieves an attribute from a specific audio stream in R3. */ 587 # define DEVAC97_CTX_SUFF_SD(a_Var, a_SD) a_Var##R3[a_SD] 588 #endif 589 558 590 /** 559 591 * Releases the AC'97 lock. … … 565 597 * Acquires the TM lock and AC'97 lock, returns on failure. 566 598 */ 567 #define DEVAC97_LOCK_BOTH_RETURN_VOID(a_pThis ) \599 #define DEVAC97_LOCK_BOTH_RETURN_VOID(a_pThis, a_SD) \ 568 600 do { \ 569 int rcLock = TMTimerLock((a_pThis)-> CTX_SUFF(pTimer), VERR_IGNORED); \601 int rcLock = TMTimerLock((a_pThis)->DEVAC97_CTX_SUFF_SD(pTimer, a_SD), VERR_IGNORED); \ 570 602 if (rcLock != VINF_SUCCESS) \ 571 603 { \ … … 577 609 { \ 578 610 AssertRC(rcLock); \ 579 TMTimerUnlock((a_pThis)-> CTX_SUFF(pTimer)); \611 TMTimerUnlock((a_pThis)->DEVAC97_CTX_SUFF_SD(pTimer, a_SD)); \ 580 612 return; \ 581 613 } \ … … 585 617 * Acquires the TM lock and AC'97 lock, returns on failure. 586 618 */ 587 #define DEVAC97_LOCK_BOTH_RETURN(a_pThis, a_ rcBusy) \619 #define DEVAC97_LOCK_BOTH_RETURN(a_pThis, a_SD, a_rcBusy) \ 588 620 do { \ 589 int rcLock = TMTimerLock((a_pThis)-> CTX_SUFF(pTimer), (a_rcBusy)); \621 int rcLock = TMTimerLock((a_pThis)->DEVAC97_CTX_SUFF_SD(pTimer, a_SD), (a_rcBusy)); \ 590 622 if (rcLock != VINF_SUCCESS) \ 591 623 return rcLock; \ … … 594 626 { \ 595 627 AssertRC(rcLock); \ 596 TMTimerUnlock((a_pThis)-> CTX_SUFF(pTimer)); \628 TMTimerUnlock((a_pThis)->DEVAC97_CTX_SUFF_SD(pTimer, a_SD)); \ 597 629 return rcLock; \ 598 630 } \ … … 602 634 * Releases the AC'97 lock and TM lock. 603 635 */ 604 #define DEVAC97_UNLOCK_BOTH(a_pThis ) \636 #define DEVAC97_UNLOCK_BOTH(a_pThis, a_SD) \ 605 637 do { \ 606 638 PDMCritSectLeave(&(a_pThis)->CritSect); \ 607 TMTimerUnlock((a_pThis)-> CTX_SUFF(pTimer)); \639 TMTimerUnlock((a_pThis)->DEVAC97_CTX_SUFF_SD(pTimer, a_SD)); \ 608 640 } while (0) 609 641 … … 636 668 static DECLCALLBACK(void) ichac97R3Reset(PPDMDEVINS pDevIns); 637 669 638 static int ichac97R3TimerStart(PAC97STATE pThis);639 static int ichac97R3TimerMaybeStart(PAC97STATE pThis);640 static int ichac97R3TimerStop(PAC97STATE pThis);641 static int ichac97R3TimerMaybeStop(PAC97STATE pThis);642 static void ichac97R3TimerMain(PAC97STATE pThis);643 670 static DECLCALLBACK(void) ichac97R3Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser); 644 645 static void ichac97R3DoTransfers(PAC97STATE pThis);646 671 647 672 static int ichac97R3MixerAddDrv(PAC97STATE pThis, PAC97DRIVER pDrv); … … 663 688 664 689 DECLINLINE(PDMAUDIODIR) ichac97GetDirFromSD(uint8_t uSD); 690 691 # ifdef LOG_ENABLED 692 static void ichac97R3BDLEDumpAll(PAC97STATE pThis, uint64_t u64BDLBase, uint16_t cBDLE); 693 # endif 665 694 #endif /* IN_RING3 */ 666 695 … … 714 743 PAC97BMREGS pRegs = &pStream->Regs; 715 744 716 uint32_t u32[2]; 717 718 PDMDevHlpPhysRead(pDevIns, pRegs->bdbar + pRegs->civ * 8, &u32[0], sizeof(u32)); 745 AC97BDLE BDLE; 746 PDMDevHlpPhysRead(pDevIns, pRegs->bdbar + pRegs->civ * sizeof(AC97BDLE), &BDLE, sizeof(AC97BDLE)); 719 747 pRegs->bd_valid = 1; 720 748 # ifndef RT_LITTLE_ENDIAN 721 749 # error "Please adapt the code (audio buffers are little endian)!" 722 750 # else 723 pRegs->bd.addr = RT_H2LE_U32( u32[0]& ~3);724 pRegs->bd.ctl_len = RT_H2LE_U32( u32[1]);751 pRegs->bd.addr = RT_H2LE_U32(BDLE.addr & ~3); 752 pRegs->bd.ctl_len = RT_H2LE_U32(BDLE.ctl_len); 725 753 # endif 726 754 pRegs->picb = pRegs->bd.ctl_len & AC97_BD_LEN_MASK; … … 779 807 { 780 808 static uint32_t const s_aMasks[] = { AC97_GS_PIINT, AC97_GS_POINT, AC97_GS_MINT }; 809 Assert(pStream->u8SD < AC97_MAX_STREAMS); 781 810 if (iIRQL) 782 811 pThis->glob_sta |= s_aMasks[pStream->u8SD]; … … 876 905 ichac97R3StreamUnlock(pStream); 877 906 878 /* Second, see if we need to start or stop the timer. */ 879 if (!fEnable) 880 ichac97R3TimerMaybeStop(pThis); 881 else 882 ichac97R3TimerMaybeStart(pThis); 883 884 LogFunc(("[SD%RU8] cStreamsActive=%RU8, fEnable=%RTbool, rc=%Rrc\n", pStream->u8SD, pThis->cStreamsActive, fEnable, rc)); 907 LogFunc(("[SD%RU8] fEnable=%RTbool, rc=%Rrc\n", pStream->u8SD, fEnable, rc)); 885 908 return rc; 886 909 } … … 927 950 * @param pThis AC'97 state. 928 951 * @param pStream AC'97 stream to create. 929 * @param u8S trm Stream ID to assign AC'97 stream to.930 */ 931 static int ichac97R3StreamCreate(PAC97STATE pThis, PAC97STREAM pStream, uint8_t u8S trm)952 * @param u8SD Stream descriptor number to assign. 953 */ 954 static int ichac97R3StreamCreate(PAC97STATE pThis, PAC97STREAM pStream, uint8_t u8SD) 932 955 { 933 956 RT_NOREF(pThis); … … 935 958 /** @todo Validate u8Strm. */ 936 959 937 LogFunc(("[SD%RU8] pStream=%p\n", u8Strm, pStream)); 938 939 Assert(u8Strm < 3); 940 pStream->u8SD = u8Strm; 960 LogFunc(("[SD%RU8] pStream=%p\n", u8SD, pStream)); 961 962 AssertReturn(u8SD < AC97_MAX_STREAMS, VERR_INVALID_PARAMETER); 963 pStream->u8SD = u8SD; 964 pStream->pAC97State = pThis; 941 965 942 966 int rc = RTCritSectInit(&pStream->State.CritSect); … … 1033 1057 * Destroy all AC'97 streams. 1034 1058 */ 1035 1036 ichac97R3StreamDestroy(pThis, &pThis->StreamLineIn); 1037 ichac97R3StreamDestroy(pThis, &pThis->StreamMicIn); 1038 ichac97R3StreamDestroy(pThis, &pThis->StreamOut); 1059 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++) 1060 ichac97R3StreamDestroy(pThis, &pThis->aStreams[i]); 1039 1061 1040 1062 /* … … 1111 1133 RTCircBufReleaseWriteBlock(pCircBuf, cbRead); 1112 1134 1113 pDstStream->State.tsLastReadWriteNs = RTTimeNanoTS();1114 1115 1135 if (pcbWritten) 1116 1136 *pcbWritten = cbRead; … … 1181 1201 } 1182 1202 1183 pSrcStream->State.tsLastReadWriteNs = RTTimeNanoTS();1184 1185 1203 if (pcbRead) 1186 1204 *pcbRead = cbReadTotal; … … 1399 1417 } 1400 1418 #endif 1401 1402 1419 # endif /* VBOX_WITH_AUDIO_AC97_ASYNC_IO */ 1420 1421 # ifdef LOG_ENABLED 1422 static void ichac97R3BDLEDumpAll(PAC97STATE pThis, uint64_t u64BDLBase, uint16_t cBDLE) 1423 { 1424 LogFlowFunc(("BDLEs @ 0x%x (%RU16):\n", u64BDLBase, cBDLE)); 1425 if (!u64BDLBase) 1426 return; 1427 1428 uint32_t cbBDLE = 0; 1429 for (uint16_t i = 0; i < cBDLE; i++) 1430 { 1431 AC97BDLE BDLE; 1432 PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), u64BDLBase + i * sizeof(AC97BDLE), &BDLE, sizeof(AC97BDLE)); 1433 1434 BDLE.addr = RT_H2LE_U32(BDLE.addr & ~3); 1435 BDLE.ctl_len = RT_H2LE_U32(BDLE.ctl_len); 1436 1437 LogFunc(("\t#%03d BDLE(adr:0x%llx, size:%RU32 [%RU32 bytes])\n", 1438 i, BDLE.addr, 1439 BDLE.ctl_len & AC97_BD_LEN_MASK, 1440 (BDLE.ctl_len & AC97_BD_LEN_MASK) << 1)); /** @todo r=andy Assumes 16bit samples. */ 1441 1442 cbBDLE += (BDLE.ctl_len & AC97_BD_LEN_MASK) << 1; /** @todo r=andy Ditto. */ 1443 } 1444 1445 LogFlowFunc(("Total: %RU32 bytes\n", cbBDLE)); 1446 } 1447 # endif /* LOG_ENABLED */ 1403 1448 1404 1449 /** … … 1444 1489 # endif 1445 1490 { 1491 uint32_t cbTransferChunk = (pStream->State.Cfg.Props.uHz / pStream->State.uTimerHz) 1492 * DrvAudioHlpPCMPropsBytesPerFrame(&pStream->State.Cfg.Props); 1493 1446 1494 const uint32_t cbStreamFree = ichac97R3StreamGetFree(pStream); 1447 1495 if (cbStreamFree) 1448 1496 { 1449 1497 /* Do the DMA transfer. */ 1450 rc2 = ichac97R3StreamTransfer(pThis, pStream, cbStreamFree);1498 rc2 = ichac97R3StreamTransfer(pThis, pStream, RT_MIN(cbStreamFree, cbTransferChunk)); 1451 1499 AssertRC(rc2); 1452 1500 } … … 1775 1823 int rc = VINF_SUCCESS; 1776 1824 1777 if (DrvAudioHlpStreamCfgIsValid(&pThis->StreamLineIn.State.Cfg)) 1778 { 1779 int rc2 = ichac97R3MixerAddDrvStream(pThis, pThis->pSinkLineIn, &pThis->StreamLineIn.State.Cfg, pDrv); 1825 if (DrvAudioHlpStreamCfgIsValid(&pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX].State.Cfg)) 1826 { 1827 int rc2 = ichac97R3MixerAddDrvStream(pThis, pThis->pSinkLineIn, 1828 &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX].State.Cfg, pDrv); 1780 1829 if (RT_SUCCESS(rc)) 1781 1830 rc = rc2; 1782 1831 } 1783 1832 1784 if (DrvAudioHlpStreamCfgIsValid(&pThis->StreamMicIn.State.Cfg)) 1785 { 1786 int rc2 = ichac97R3MixerAddDrvStream(pThis, pThis->pSinkMicIn, &pThis->StreamMicIn.State.Cfg, pDrv); 1833 if (DrvAudioHlpStreamCfgIsValid(&pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX].State.Cfg)) 1834 { 1835 int rc2 = ichac97R3MixerAddDrvStream(pThis, pThis->pSinkOut, 1836 &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX].State.Cfg, pDrv); 1787 1837 if (RT_SUCCESS(rc)) 1788 1838 rc = rc2; 1789 1839 } 1790 1840 1791 if (DrvAudioHlpStreamCfgIsValid(&pThis->StreamOut.State.Cfg)) 1792 { 1793 int rc2 = ichac97R3MixerAddDrvStream(pThis, pThis->pSinkOut, &pThis->StreamOut.State.Cfg, pDrv); 1841 if (DrvAudioHlpStreamCfgIsValid(&pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX].State.Cfg)) 1842 { 1843 int rc2 = ichac97R3MixerAddDrvStream(pThis, pThis->pSinkMicIn, 1844 &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX].State.Cfg, pDrv); 1794 1845 if (RT_SUCCESS(rc)) 1795 1846 rc = rc2; … … 1979 2030 } 1980 2031 1981 rc = RTCircBufCreate(&pStream->State.pCircBuf, DrvAudioHlpMilliToBytes( 500 /* ms */, &Cfg.Props)); /** @todo Make this configurable. */2032 rc = RTCircBufCreate(&pStream->State.pCircBuf, DrvAudioHlpMilliToBytes(100 /* ms */, &Cfg.Props)); /** @todo Make this configurable. */ 1982 2033 if (RT_SUCCESS(rc)) 1983 2034 { … … 1988 2039 rc = DrvAudioHlpStreamCfgCopy(&pStream->State.Cfg, &Cfg); 1989 2040 } 2041 2042 /* 2043 * Set the stream's timer Hz rate. 2044 * 2045 * Currently we simply apply the global Hz rate. 2046 * This might needs tweaking as we add surround support and/or channel striping later. */ 2047 pStream->State.uTimerHz = pThis->uTimerHz; 2048 2049 /* 2050 * Set up data transfer stuff. 2051 */ 2052 #ifdef LOG_ENABLED 2053 ichac97R3BDLEDumpAll(pThis, pStream->Regs.bdbar, pStream->Regs.lvi + 1); 2054 #endif 2055 const uint32_t cbFrame = DrvAudioHlpPCMPropsBytesPerFrame(&Cfg.Props); 2056 2057 /* Calculate the fragment size the guest OS expects interrupt delivery at. */ 2058 pStream->State.cbTransferSize = 441 * 4;//pStream->u32CBL / cFragments; 2059 Assert(pStream->State.cbTransferSize); 2060 Assert(pStream->State.cbTransferSize % cbFrame == 0); 2061 2062 /* Calculate the bytes we need to transfer to / from the stream's DMA per iteration. 2063 * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. */ 2064 pStream->State.cbTransferChunk = (pStream->State.Cfg.Props.uHz / pStream->State.uTimerHz) * cbFrame; 2065 Assert(pStream->State.cbTransferChunk); 2066 Assert(pStream->State.cbTransferChunk % cbFrame== 0); 2067 2068 /* Make sure that the transfer chunk does not exceed the overall transfer size. */ 2069 if (pStream->State.cbTransferChunk > pStream->State.cbTransferSize) 2070 pStream->State.cbTransferChunk = pStream->State.cbTransferSize; 2071 2072 const uint64_t cTicksPerHz = TMTimerGetFreq((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD))/ pStream->State.uTimerHz; 2073 2074 /* Calculate the timer ticks per byte for this stream. */ 2075 pStream->State.cTicksPerByte = cTicksPerHz / pStream->State.cbTransferChunk; 2076 Assert(pStream->State.cTicksPerByte); 2077 2078 /* Calculate timer ticks per transfer. */ 2079 pStream->State.cTransferTicks = pStream->State.cbTransferChunk * pStream->State.cTicksPerByte; 2080 Assert(pStream->State.cTransferTicks); 2081 2082 LogFunc(("[SD%RU8] Timer %uHz (%RU64 ticks per Hz), cTicksPerByte=%RU64, cbTransferChunk=%RU32, cTransferTicks=%RU64, " \ 2083 "cbTransferSize=%RU32\n", 2084 pStream->u8SD, pStream->State.uTimerHz, cTicksPerHz, pStream->State.cTicksPerByte, 2085 pStream->State.cbTransferChunk, pStream->State.cTransferTicks, pStream->State.cbTransferSize)); 2086 1990 2087 } 1991 2088 } … … 2342 2439 } 2343 2440 2441 AssertFailed(); 2344 2442 return PDMAUDIODIR_UNKNOWN; 2345 2443 } 2346 2444 2347 2445 #endif /* IN_RING3 */ 2348 2349 /**2350 * Retrieves an AC'97 audio stream from an AC'97 stream index.2351 *2352 * @returns Pointer to AC'97 audio stream if found, or NULL if not found / invalid.2353 * @param pThis AC'97 state.2354 * @param uIdx AC'97 stream index to retrieve AC'97 audio stream for.2355 */2356 DECLINLINE(PAC97STREAM) ichac97GetStreamFromIdx(PAC97STATE pThis, uint32_t uIdx)2357 {2358 switch (uIdx)2359 {2360 case AC97SOUNDSOURCE_PI_INDEX: return &pThis->StreamLineIn;2361 case AC97SOUNDSOURCE_MC_INDEX: return &pThis->StreamMicIn;2362 case AC97SOUNDSOURCE_PO_INDEX: return &pThis->StreamOut;2363 default: return NULL;2364 }2365 2366 }2367 2446 2368 2447 #ifdef IN_RING3 … … 2502 2581 2503 2582 /** 2504 * Starts the internal audio device timer.2505 *2506 * @return IPRT status code.2507 * @param pThis AC'97 state.2508 */2509 static int ichac97R3TimerStart(PAC97STATE pThis)2510 {2511 LogFlowFuncEnter();2512 2513 DEVAC97_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);2514 2515 AssertPtr(pThis->CTX_SUFF(pTimer));2516 2517 if (!pThis->fTimerActive)2518 {2519 LogRel2(("AC97: Starting transfers\n"));2520 2521 pThis->fTimerActive = true;2522 2523 /* Start transfers. */2524 ichac97R3TimerMain(pThis);2525 }2526 2527 DEVAC97_UNLOCK_BOTH(pThis);2528 2529 return VINF_SUCCESS;2530 }2531 2532 /**2533 * Starts the internal audio device timer (if not started yet).2534 *2535 * @return IPRT status code.2536 * @param pThis AC'97 state.2537 */2538 static int ichac97R3TimerMaybeStart(PAC97STATE pThis)2539 {2540 LogFlowFuncEnter();2541 2542 if (!pThis->CTX_SUFF(pTimer))2543 return VERR_WRONG_ORDER;2544 2545 pThis->cStreamsActive++;2546 2547 /* Only start the timer at the first active stream. */2548 if (pThis->cStreamsActive == 1)2549 return ichac97R3TimerStart(pThis);2550 2551 return VINF_SUCCESS;2552 }2553 2554 /**2555 * Stops the internal audio device timer.2556 *2557 * @return IPRT status code.2558 * @param pThis AC'97 state.2559 */2560 static int ichac97R3TimerStop(PAC97STATE pThis)2561 {2562 LogFlowFuncEnter();2563 2564 if (!pThis->CTX_SUFF(pTimer)) /* Only can happen on device construction time, so no locking needed here. */2565 return VINF_SUCCESS;2566 2567 DEVAC97_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_MMIO_WRITE);2568 2569 if (pThis->fTimerActive)2570 {2571 LogRel2(("AC97: Stopping transfers ...\n"));2572 2573 pThis->fTimerActive = false;2574 2575 /* Note: Do not stop the timer via TMTimerStop() here, as there still might2576 * be queued audio data which needs to be handled (e.g. played back) first2577 * before actually stopping the timer for good. */2578 }2579 2580 DEVAC97_UNLOCK_BOTH(pThis);2581 2582 return VINF_SUCCESS;2583 }2584 2585 /**2586 * Decreases the active AC'97 streams count by one and2587 * then checks if the internal audio device timer can be2588 * stopped.2589 *2590 * @return IPRT status code.2591 * @param pThis AC'97 state.2592 */2593 static int ichac97R3TimerMaybeStop(PAC97STATE pThis)2594 {2595 LogFlowFuncEnter();2596 2597 if (!pThis->CTX_SUFF(pTimer))2598 return VERR_WRONG_ORDER;2599 2600 if (pThis->cStreamsActive) /* Function can be called mupltiple times. */2601 {2602 pThis->cStreamsActive--;2603 2604 if (pThis->cStreamsActive == 0)2605 return ichac97R3TimerStop(pThis);2606 }2607 2608 return VINF_SUCCESS;2609 }2610 2611 /**2612 * Main routine for the device timer.2613 *2614 * @param pThis AC'97 state.2615 */2616 static void ichac97R3TimerMain(PAC97STATE pThis)2617 {2618 STAM_PROFILE_START(&pThis->StatTimer, a);2619 2620 DEVAC97_LOCK_BOTH_RETURN_VOID(pThis);2621 2622 uint64_t cTicksNow = TMTimerGet(pThis->CTX_SUFF(pTimer));2623 2624 /* Update current time timestamp. */2625 pThis->uTimerTS = cTicksNow;2626 2627 /* Flag indicating whether to arm the timer again for the next DMA transfer or sink processing. */2628 bool fArmTimer = false;2629 2630 ichac97R3DoTransfers(pThis);2631 2632 /* Do we need to arm the timer again? */2633 if ( AudioMixerSinkIsActive(ichac97R3IndexToSink(pThis, pThis->StreamLineIn.u8SD))2634 || AudioMixerSinkIsActive(ichac97R3IndexToSink(pThis, pThis->StreamMicIn.u8SD))2635 || AudioMixerSinkIsActive(ichac97R3IndexToSink(pThis, pThis->StreamOut.u8SD)))2636 {2637 fArmTimer = true;2638 }2639 2640 if ( ASMAtomicReadBool(&pThis->fTimerActive) /** @todo r=bird: totally unnecessary to do atomic read here, isn't it? */2641 || fArmTimer)2642 {2643 /* Arm the timer again. */2644 uint64_t cTicks = pThis->cTimerTicks;2645 /** @todo adjust cTicks down by now much cbOutMin represents. */2646 TMTimerSet(pThis->CTX_SUFF(pTimer), cTicksNow + cTicks);2647 }2648 else2649 LogRel2(("AC97: Stopped transfers\n"));2650 2651 DEVAC97_UNLOCK_BOTH(pThis);2652 2653 STAM_PROFILE_STOP(&pThis->StatTimer, a);2654 }2655 2656 /**2657 2583 * Timer callback which handles the audio data transfers on a periodic basis. 2658 2584 * … … 2665 2591 RT_NOREF(pDevIns, pTimer); 2666 2592 2667 PAC97STATE pThis = (PAC97STATE)pvUser; 2668 Assert(pThis == PDMINS_2_DATA(pDevIns, PAC97STATE)); 2669 2670 ichac97R3TimerMain(pThis); 2671 } 2672 2673 /** 2674 * Main routine to perform the actual audio data transfers from the AC'97 streams 2675 * to the backend(s) and vice versa. 2676 * 2593 PAC97STREAM pStream = (PAC97STREAM)pvUser; 2594 AssertPtr(pStream); 2595 2596 PAC97STATE pThis = pStream->pAC97State; 2597 AssertPtr(pThis); 2598 2599 STAM_PROFILE_START(&pThis->StatTimer, a); 2600 2601 DEVAC97_LOCK_BOTH_RETURN_VOID(pThis, pStream->u8SD); 2602 2603 ichac97R3StreamUpdate(pThis, pStream, true /* fInTimer */); 2604 2605 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThis, pStream->u8SD); 2606 2607 bool fSinkActive = false; 2608 if (pSink) 2609 fSinkActive = AudioMixerSinkIsActive(pSink); 2610 2611 if (fSinkActive) 2612 { 2613 TMTimerSet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD), 2614 TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks); 2615 } 2616 2617 DEVAC97_UNLOCK_BOTH(pThis, pStream->u8SD); 2618 2619 STAM_PROFILE_STOP(&pThis->StatTimer, a); 2620 } 2621 2622 /** 2623 * Sets the virtual device timer to a new expiration time. 2624 * 2625 * @returns Whether the new expiration time was set or not. 2677 2626 * @param pThis AC'97 state. 2678 */ 2679 static void ichac97R3DoTransfers(PAC97STATE pThis) 2680 { 2681 AssertPtrReturnVoid(pThis); 2682 2683 ichac97R3StreamUpdate(pThis, &pThis->StreamLineIn, true /* fInTimer */); 2684 ichac97R3StreamUpdate(pThis, &pThis->StreamMicIn, true /* fInTimer */); 2685 ichac97R3StreamUpdate(pThis, &pThis->StreamOut, true /* fInTimer */); 2627 * @param pStream AC'97 stream to set timer for. 2628 * @param tsExpire New (virtual) expiration time to set. 2629 * @param fForce Whether to force setting the expiration time or not. 2630 * 2631 * @remark This function takes all active AC'97 streams and their 2632 * current timing into account. This is needed to make sure 2633 * that all streams can match their needed timing. 2634 * 2635 * To achieve this, the earliest (lowest) timestamp of all 2636 * active streams found will be used for the next scheduling slot. 2637 * 2638 * Forcing a new expiration time will override the above mechanism. 2639 */ 2640 bool ichac97R3TimerSet(PAC97STATE pThis, PAC97STREAM pStream, uint64_t tsExpire, bool fForce) 2641 { 2642 AssertPtrReturn(pThis, false); 2643 AssertPtrReturn(pStream, false); 2644 2645 RT_NOREF(fForce); 2646 2647 uint64_t tsExpireMin = tsExpire; 2648 2649 AssertPtr((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)); 2650 2651 const uint64_t tsNow = TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)); 2652 2653 /* Make sure to not go backwards in time, as this will assert in TMTimerSet(). */ 2654 if (tsExpireMin < tsNow) 2655 tsExpireMin = tsNow; 2656 2657 int rc = TMTimerSet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD), tsExpireMin); 2658 AssertRC(rc); 2659 2660 return RT_SUCCESS(rc); 2686 2661 } 2687 2662 … … 2891 2866 } 2892 2867 2893 pStream->State.tsLastTransferNs = RTTimeNanoTS();2894 2895 2868 ichac97R3StreamUnlock(pStream); 2896 2869 … … 2925 2898 const uint32_t uPortIdx = uPort - pThis->IOPortBase[1]; 2926 2899 2927 PAC97STREAM pStream = ichac97GetStreamFromIdx(pThis, AC97_PORT2IDX(uPortIdx));2900 PAC97STREAM pStream = NULL; 2928 2901 PAC97BMREGS pRegs = NULL; 2929 2902 2930 if (pStream) /* Can be NULL, depending on the index (port). */ 2931 pRegs = &pStream->Regs; 2903 if (AC97_PORT2IDX(uPortIdx) < AC97_MAX_STREAMS) 2904 { 2905 pStream = &pThis->aStreams[AC97_PORT2IDX(uPortIdx)]; 2906 AssertPtr(pStream); 2907 pRegs = &pStream->Regs; 2908 } 2932 2909 2933 2910 int rc = VINF_SUCCESS; … … 3091 3068 RT_NOREF(pvUser); 3092 3069 3093 DEVAC97_LOCK_BOTH_RETURN(pThis, VINF_IOM_R3_IOPORT_WRITE);3094 3095 3070 /* Get the index of the NABMBAR register. */ 3096 3071 const uint32_t uPortIdx = uPort - pThis->IOPortBase[1]; 3097 3072 3098 PAC97STREAM pStream = ichac97GetStreamFromIdx(pThis, AC97_PORT2IDX(uPortIdx));3073 PAC97STREAM pStream = NULL; 3099 3074 PAC97BMREGS pRegs = NULL; 3100 3075 3101 if (pStream) /* Can be NULL, depending on the index (port). */ 3076 if (AC97_PORT2IDX(uPortIdx) < AC97_MAX_STREAMS) 3077 { 3078 pStream = &pThis->aStreams[AC97_PORT2IDX(uPortIdx)]; 3079 AssertPtr(pStream); 3102 3080 pRegs = &pStream->Regs; 3081 3082 DEVAC97_LOCK_BOTH_RETURN(pThis, pStream->u8SD, VINF_IOM_R3_IOPORT_WRITE); 3083 } 3103 3084 3104 3085 int rc = VINF_SUCCESS; … … 3116 3097 case MC_LVI: 3117 3098 { 3099 AssertPtr(pStream); 3100 AssertPtr(pRegs); 3118 3101 if ( (pRegs->cr & AC97_CR_RPBM) 3119 3102 && (pRegs->sr & AC97_SR_DCH)) … … 3141 3124 case MC_CR: 3142 3125 { 3126 AssertPtr(pStream); 3127 AssertPtr(pRegs); 3143 3128 #ifdef IN_RING3 3144 3129 Log3Func(("[SD%RU8] CR <- %#x (cr %#x)\n", pStream->u8SD, u32Val, pRegs->cr)); … … 3178 3163 /* Fetch the initial BDLE descriptor. */ 3179 3164 ichac97R3StreamFetchBDLE(pThis, pStream); 3180 3181 3165 ichac97R3StreamEnable(pThis, pStream, true /* fEnable */); 3166 3167 /* Arm the timer for this stream. */ 3168 int rc2 = ichac97R3TimerSet(pThis, pStream, 3169 TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks, 3170 false /* fForce */); 3171 AssertRC(rc2); 3182 3172 } 3183 3173 } … … 3195 3185 case MC_SR: 3196 3186 { 3187 AssertPtr(pStream); 3188 AssertPtr(pRegs); 3197 3189 pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK); 3198 3190 ichac97StreamUpdateSR(pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK)); … … 3215 3207 case PO_SR: 3216 3208 case MC_SR: 3209 AssertPtr(pStream); 3210 AssertPtr(pRegs); 3217 3211 /* Status Register */ 3218 3212 pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK); … … 3234 3228 case PO_BDBAR: 3235 3229 case MC_BDBAR: 3230 AssertPtr(pStream); 3231 AssertPtr(pRegs); 3236 3232 /* Buffer Descriptor list Base Address Register */ 3237 3233 pRegs->bdbar = u32Val & ~3; … … 3266 3262 } 3267 3263 3268 DEVAC97_UNLOCK_BOTH(pThis); 3264 if (pStream) 3265 DEVAC97_UNLOCK_BOTH(pThis, pStream->u8SD); 3269 3266 3270 3267 return rc; … … 3350 3347 RT_NOREF(pvUser); 3351 3348 3352 DEVAC97_LOCK_ BOTH_RETURN(pThis, VINF_IOM_R3_IOPORT_WRITE);3349 DEVAC97_LOCK_RETURN(pThis, VINF_IOM_R3_IOPORT_WRITE); 3353 3350 3354 3351 uint32_t uPortIdx = uPort - pThis->IOPortBase[0]; 3352 3355 3353 int rc = VINF_SUCCESS; 3356 3354 switch (cbVal) … … 3456 3454 { 3457 3455 ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate, 48000); 3458 ichac97R3StreamReOpen(pThis, &pThis-> StreamOut);3456 ichac97R3StreamReOpen(pThis, &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX]); 3459 3457 3460 3458 ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate, 48000); 3461 ichac97R3StreamReOpen(pThis, &pThis-> StreamLineIn);3459 ichac97R3StreamReOpen(pThis, &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX]); 3462 3460 } 3463 3461 else … … 3467 3465 { 3468 3466 ichac97MixerSet(pThis, AC97_MIC_ADC_Rate, 48000); 3469 ichac97R3StreamReOpen(pThis, &pThis-> StreamMicIn);3467 ichac97R3StreamReOpen(pThis, &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX]); 3470 3468 } 3471 3469 else … … 3484 3482 ichac97MixerSet(pThis, uPortIdx, u32Val); 3485 3483 LogFunc(("Set front DAC rate to %RU32\n", u32Val)); 3486 ichac97R3StreamReOpen(pThis, &pThis-> StreamOut);3484 ichac97R3StreamReOpen(pThis, &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX]); 3487 3485 #else 3488 3486 rc = VINF_IOM_R3_IOPORT_WRITE; … … 3498 3496 ichac97MixerSet(pThis, uPortIdx, u32Val); 3499 3497 LogFunc(("Set MIC ADC rate to %RU32\n", u32Val)); 3500 ichac97R3StreamReOpen(pThis, &pThis-> StreamMicIn);3498 ichac97R3StreamReOpen(pThis, &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX]); 3501 3499 #else 3502 3500 rc = VINF_IOM_R3_IOPORT_WRITE; … … 3512 3510 ichac97MixerSet(pThis, uPortIdx, u32Val); 3513 3511 LogFunc(("Set front LR ADC rate to %RU32\n", u32Val)); 3514 ichac97R3StreamReOpen(pThis, &pThis-> StreamLineIn);3512 ichac97R3StreamReOpen(pThis, &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX]); 3515 3513 #else 3516 3514 rc = VINF_IOM_R3_IOPORT_WRITE; … … 3540 3538 } 3541 3539 3542 DEVAC97_UNLOCK _BOTH(pThis);3540 DEVAC97_UNLOCK(pThis); 3543 3541 3544 3542 return rc; … … 3643 3641 3644 3642 /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */ 3645 /* Note: The order the streams are saved here is critical, so don't touch. */ 3646 int rc2 = ichac97R3SaveStream(pDevIns, pSSM, &pThis->StreamLineIn); 3647 AssertRC(rc2); 3648 rc2 = ichac97R3SaveStream(pDevIns, pSSM, &pThis->StreamOut); 3649 AssertRC(rc2); 3650 rc2 = ichac97R3SaveStream(pDevIns, pSSM, &pThis->StreamMicIn); 3651 AssertRC(rc2); 3643 /* Note: The order the streams are loaded here is critical, so don't touch. */ 3644 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++) 3645 { 3646 int rc2 = ichac97R3SaveStream(pDevIns, pSSM, &pThis->aStreams[i]); 3647 AssertRC(rc2); 3648 } 3652 3649 3653 3650 SSMR3PutMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data)); … … 3655 3652 uint8_t active[AC97SOUNDSOURCE_END_INDEX]; 3656 3653 3657 active[AC97SOUNDSOURCE_PI_INDEX] = ichac97R3StreamIsEnabled(pThis, &pThis-> StreamLineIn) ? 1 : 0;3658 active[AC97SOUNDSOURCE_PO_INDEX] = ichac97R3StreamIsEnabled(pThis, &pThis-> StreamOut)? 1 : 0;3659 active[AC97SOUNDSOURCE_MC_INDEX] = ichac97R3StreamIsEnabled(pThis, &pThis-> StreamMicIn)? 1 : 0;3654 active[AC97SOUNDSOURCE_PI_INDEX] = ichac97R3StreamIsEnabled(pThis, &pThis->aStreams[AC97SOUNDSOURCE_PI_INDEX]) ? 1 : 0; 3655 active[AC97SOUNDSOURCE_PO_INDEX] = ichac97R3StreamIsEnabled(pThis, &pThis->aStreams[AC97SOUNDSOURCE_PO_INDEX]) ? 1 : 0; 3656 active[AC97SOUNDSOURCE_MC_INDEX] = ichac97R3StreamIsEnabled(pThis, &pThis->aStreams[AC97SOUNDSOURCE_MC_INDEX]) ? 1 : 0; 3660 3657 3661 3658 SSMR3PutMem(pSSM, active, sizeof(active)); … … 3706 3703 /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */ 3707 3704 /* Note: The order the streams are loaded here is critical, so don't touch. */ 3708 int rc2 = ichac97R3LoadStream(pSSM, &pThis->StreamLineIn); 3709 AssertRCReturn(rc2, rc2); 3710 rc2 = ichac97R3LoadStream(pSSM, &pThis->StreamOut); 3711 AssertRCReturn(rc2, rc2); 3712 rc2 = ichac97R3LoadStream(pSSM, &pThis->StreamMicIn); 3713 AssertRCReturn(rc2, rc2); 3705 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++) 3706 { 3707 int rc2 = ichac97R3LoadStream(pSSM, &pThis->aStreams[i]); 3708 AssertRCReturn(rc2, rc2); 3709 } 3714 3710 3715 3711 SSMR3GetMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data)); … … 3717 3713 /** @todo r=andy Stream IDs are hardcoded to certain streams. */ 3718 3714 uint8_t uaStrmsActive[AC97SOUNDSOURCE_END_INDEX]; 3719 rc2 = SSMR3GetMem(pSSM, uaStrmsActive, sizeof(uaStrmsActive));3715 int rc2 = SSMR3GetMem(pSSM, uaStrmsActive, sizeof(uaStrmsActive)); 3720 3716 AssertRCReturn(rc2, rc2); 3721 3717 … … 3733 3729 3734 3730 /** @todo r=andy Stream IDs are hardcoded to certain streams. */ 3735 rc2 = ichac97R3StreamEnable(pThis, &pThis->StreamLineIn, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_PI_INDEX])); 3736 if (RT_SUCCESS(rc2)) 3737 rc2 = ichac97R3StreamEnable(pThis, &pThis->StreamMicIn, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_MC_INDEX])); 3738 if (RT_SUCCESS(rc2)) 3739 rc2 = ichac97R3StreamEnable(pThis, &pThis->StreamOut, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_PO_INDEX])); 3731 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++) 3732 { 3733 rc2 = ichac97R3StreamEnable(pThis, &pThis->aStreams[i], RT_BOOL(uaStrmsActive[i])); 3734 AssertRC(rc2); 3735 /* Keep going. */ 3736 } 3740 3737 3741 3738 pThis->bup_flag = 0; … … 3809 3806 * Reset all streams. 3810 3807 */ 3811 ichac97R3StreamEnable(pThis, &pThis->StreamLineIn, false /* fEnable */); 3812 ichac97R3StreamReset(pThis, &pThis->StreamLineIn); 3813 3814 ichac97R3StreamEnable(pThis, &pThis->StreamMicIn, false /* fEnable */); 3815 ichac97R3StreamReset(pThis, &pThis->StreamMicIn); 3816 3817 ichac97R3StreamEnable(pThis, &pThis->StreamOut, false /* fEnable */); 3818 ichac97R3StreamReset(pThis, &pThis->StreamOut); 3808 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++) 3809 { 3810 ichac97R3StreamEnable(pThis, &pThis->aStreams[i], false /* fEnable */); 3811 ichac97R3StreamReset(pThis, &pThis->aStreams[i]); 3812 } 3819 3813 3820 3814 /* … … 3827 3821 AudioMixerSinkReset(pThis->pSinkMicIn); 3828 3822 AudioMixerSinkReset(pThis->pSinkOut); 3829 3830 /*3831 * Stop the timer, if any.3832 */3833 ichac97R3TimerStop(pThis);3834 3835 pThis->cStreamsActive = 0;3836 3823 } 3837 3824 … … 4096 4083 PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE); 4097 4084 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 4098 pThis->pTimerRC = TMTimerRCPtr(pThis->pTimerR3); 4085 4086 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++) 4087 pThis->pTimerRC[i] = TMTimerRCPtr(pThis->pTimerR3[i]); 4099 4088 } 4100 4089 … … 4322 4311 * Create all hardware streams. 4323 4312 */ 4324 rc = ichac97R3StreamCreate(pThis, &pThis->StreamLineIn, AC97SOUNDSOURCE_PI_INDEX);4325 if (RT_SUCCESS(rc))4326 {4327 rc = ichac97R3StreamCreate(pThis, &pThis->StreamMicIn, AC97SOUNDSOURCE_MC_INDEX);4313 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++) 4314 { 4315 int rc2 = ichac97R3StreamCreate(pThis, &pThis->aStreams[i], i /* SD# */); 4316 AssertRC(rc2); 4328 4317 if (RT_SUCCESS(rc)) 4329 rc = ichac97R3StreamCreate(pThis, &pThis->StreamOut, AC97SOUNDSOURCE_PO_INDEX);4318 rc = rc2; 4330 4319 } 4331 4320 … … 4433 4422 if (RT_SUCCESS(rc)) 4434 4423 { 4435 /* Create the emulation timer. 4436 * 4437 * Note: Use TMCLOCK_VIRTUAL_SYNC here, as the guest's AC'97 driver 4438 * relies on exact (virtual) DMA timing and uses DMA Position Buffers 4439 * instead of the LPIB registers. 4440 */ 4441 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, ichac97R3Timer, pThis, 4442 TMTIMER_FLAGS_NO_CRIT_SECT, "AC'97 Timer", &pThis->pTimerR3); 4443 AssertRCReturn(rc, rc); 4444 pThis->pTimerR0 = TMTimerR0Ptr(pThis->pTimerR3); 4445 pThis->pTimerRC = TMTimerRCPtr(pThis->pTimerR3); 4446 4447 /* Use our own critcal section for the device timer. 4448 * That way we can control more fine-grained when to lock what. */ 4449 rc = TMR3TimerSetCritSect(pThis->pTimerR3, &pThis->CritSect); 4450 AssertRCReturn(rc, rc); 4451 4452 pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimerR3) / pThis->uTimerHz; 4453 pThis->uTimerTS = TMTimerGet(pThis->pTimerR3); 4454 LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, pThis->uTimerHz)); 4424 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++) 4425 { 4426 /* Create the emulation timer (per stream). 4427 * 4428 * Note: Use TMCLOCK_VIRTUAL_SYNC here, as the guest's AC'97 driver 4429 * relies on exact (virtual) DMA timing and uses DMA Position Buffers 4430 * instead of the LPIB registers. 4431 */ 4432 char szTimer[16]; 4433 RTStrPrintf2(szTimer, sizeof(szTimer), "AC97SD%i", i); 4434 4435 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, ichac97R3Timer, &pThis->aStreams[i], 4436 TMTIMER_FLAGS_NO_CRIT_SECT, szTimer, &pThis->pTimerR3[i]); 4437 AssertRCReturn(rc, rc); 4438 pThis->pTimerR0[i] = TMTimerR0Ptr(pThis->pTimerR3[i]); 4439 pThis->pTimerRC[i] = TMTimerRCPtr(pThis->pTimerR3[i]); 4440 4441 /* Use our own critcal section for the device timer. 4442 * That way we can control more fine-grained when to lock what. */ 4443 rc = TMR3TimerSetCritSect(pThis->pTimerR3[i], &pThis->CritSect); 4444 AssertRCReturn(rc, rc); 4445 } 4455 4446 } 4456 4447
Note:
See TracChangeset
for help on using the changeset viewer.