Changeset 76862 in vbox for trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
- Timestamp:
- Jan 17, 2019 1:58:54 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
r76854 r76862 349 349 * Can be 0 if no next transfer is scheduled. */ 350 350 uint64_t tsTransferNext; 351 /** Total transfer size (in bytes) of a transfer period. */352 uint32_t cbTransferSize;353 351 /** Transfer chunk size (in bytes) of a transfer period. */ 354 352 uint32_t cbTransferChunk; 355 /** How many bytes already have been processed in within356 * the current transfer period. */357 uint32_t cbTransferProcessed;358 353 /** The stream's timer Hz rate. 359 354 * This value can can be different from the device's default Hz rate, … … 362 357 uint16_t uTimerHz; 363 358 uint8_t Padding3[2]; 364 /** (Virtual) clock ticks per byte. */365 uint64_t cTicksPerByte;366 359 /** (Virtual) clock ticks per transfer. */ 367 360 uint64_t cTransferTicks; … … 706 699 # endif 707 700 #endif /* IN_RING3 */ 701 bool ichac97TimerSet(PAC97STATE pThis, PAC97STREAM pStream, uint64_t tsExpire, bool fForce); 708 702 709 703 static void ichac97WarmReset(PAC97STATE pThis) … … 833 827 } 834 828 829 /** 830 * Writes a new value to a stream's status register (SR). 831 * 832 * @param pThis AC'97 device state. 833 * @param pStream Stream to update SR for. 834 * @param u32Val New value to set the stream's SR to. 835 */ 835 836 static void ichac97StreamWriteSR(PAC97STATE pThis, PAC97STREAM pStream, uint32_t u32Val) 836 837 { … … 1506 1507 int rc2; 1507 1508 1508 if (pStream->u8SD == AC97SOUNDSOURCE_PO_INDEX) /* Output (SDO). */ 1509 { 1510 /* How much (guest output) data is available at the moment for the AC'97 stream? */ 1511 /* Only read from the AC'97 stream at the given scheduling rate. */ 1512 bool fDoRead = false; /* Whether to read from the AC'97 stream or not. */ 1513 1509 if (pStream->State.Cfg.enmDir == PDMAUDIODIR_OUT) /* Output (SDO). */ 1510 { 1514 1511 # ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 1515 1512 if (fInTimer) 1516 1513 # endif 1517 1514 { 1518 uint32_t cbTransferChunk = (pStream->State.Cfg.Props.uHz / pStream->State.uTimerHz)1519 * DrvAudioHlpPCMPropsBytesPerFrame(&pStream->State.Cfg.Props);1520 1521 1515 const uint32_t cbStreamFree = ichac97R3StreamGetFree(pStream); 1522 1516 if (cbStreamFree) 1523 1517 { 1518 Log3Func(("[SD%RU8] PICB=%zu (%RU64ms), cbFree=%zu (%RU64ms), cbTransferChunk=%zu (%RU64ms)\n", 1519 pStream->u8SD, 1520 (pStream->Regs.picb << 1), DrvAudioHlpBytesToMilli((pStream->Regs.picb << 1), &pStream->State.Cfg.Props), 1521 cbStreamFree, DrvAudioHlpBytesToMilli(cbStreamFree, &pStream->State.Cfg.Props), 1522 pStream->State.cbTransferChunk, DrvAudioHlpBytesToMilli(pStream->State.cbTransferChunk, &pStream->State.Cfg.Props))); 1523 1524 1524 /* Do the DMA transfer. */ 1525 rc2 = ichac97R3StreamTransfer(pThis, pStream, RT_MIN( cbStreamFree, cbTransferChunk));1525 rc2 = ichac97R3StreamTransfer(pThis, pStream, RT_MIN(pStream->State.cbTransferChunk, cbStreamFree)); 1526 1526 AssertRC(rc2); 1527 1528 pStream->State.tsLastUpdateNs = RTTimeNanoTS(); 1527 1529 } 1528 1529 /* Only read from the AC'97 stream at the given scheduling rate. */ 1530 const uint64_t tsNowNs = RTTimeNanoTS(); 1531 if (tsNowNs - pStream->State.tsLastUpdateNs >= pStream->State.Cfg.Device.uSchedulingHintMs * RT_NS_1MS) 1532 { 1533 fDoRead = true; 1534 pStream->State.tsLastUpdateNs = tsNowNs; 1535 } 1536 } 1537 1538 Log3Func(("[SD%RU8] fInTimer=%RTbool, fDoRead=%RTbool\n", pStream->u8SD, fInTimer, fDoRead)); 1530 } 1531 1532 Log3Func(("[SD%RU8] fInTimer=%RTbool\n", pStream->u8SD, fInTimer)); 1539 1533 1540 1534 # ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 1541 if (fDoRead) 1542 { 1543 rc2 = ichac97R3StreamAsyncIONotify(pThis, pStream); 1544 AssertRC(rc2); 1545 } 1535 rc2 = ichac97R3StreamAsyncIONotify(pThis, pStream); 1536 AssertRC(rc2); 1546 1537 # endif 1547 1538 1548 1539 # ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 1549 1540 if (!fInTimer) /* In async I/O thread */ 1550 {1551 # else1552 if (fDoRead)1553 1541 { 1554 1542 # endif … … 1565 1553 AssertRC(rc2); 1566 1554 } 1567 } 1568 1555 # ifdef VBOX_WITH_AUDIO_AC97_ASYNC_IO 1556 } 1557 #endif 1569 1558 /* When running synchronously, update the associated sink here. 1570 1559 * Otherwise this will be done in the async I/O thread. */ … … 1969 1958 1970 1959 /** 1960 * Calculates and returns the ticks for a specified amount of bytes. 1961 * 1962 * @returns Calculated ticks 1963 * @param pThis AC'97 device state. 1964 * @param pStream AC'97 stream to calculate ticks for. 1965 * @param cbBytes Bytes to calculate ticks for. 1966 */ 1967 static uint64_t ichac97R3StreamTransferCalcNext(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbBytes) 1968 { 1969 if (!cbBytes) 1970 return 0; 1971 1972 AssertReturn(DrvAudioHlpPCMPropsAreValid(&pStream->State.Cfg.Props), 0); 1973 const uint32_t cbFrame = DrvAudioHlpPCMPropsBytesPerFrame(&pStream->State.Cfg.Props); 1974 1975 AssertReturn(cbBytes % cbFrame == 0, 0); 1976 1977 const uint64_t cTicksPerHz = TMTimerGetFreq((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) / pStream->State.uTimerHz; 1978 const uint64_t cTicksPerByte = cTicksPerHz / cbBytes; 1979 Assert(cTicksPerByte); 1980 const uint64_t cTransferTicks = cbBytes * cTicksPerByte; 1981 1982 LogFunc(("[SD%RU8] Timer %uHz (%RU64 ticks per Hz), cTicksPerByte=%RU64, cbBytes=%RU32 -> cTransferTicks=%RU64\n", 1983 pStream->u8SD, pStream->State.uTimerHz, cTicksPerHz, cTicksPerByte, cbBytes, cTransferTicks)); 1984 1985 return cTransferTicks; 1986 } 1987 1988 /** 1989 * Updates the next transfer based on a specific amount of bytes. 1990 * 1991 * @returns IPRT status code. 1992 * @param pThis AC'97 device state. 1993 * @param pStream AC'97 stream to update. 1994 * @param cbBytes Bytes to update next transfer for. 1995 */ 1996 static void ichac97R3StreamTransferUpdate(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbBytes) 1997 { 1998 if (!cbBytes) 1999 return; 2000 2001 /* Calculate the bytes we need to transfer to / from the stream's DMA per iteration. 2002 * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. */ 2003 pStream->State.cbTransferChunk = cbBytes; 2004 2005 /* Update the transfer ticks. */ 2006 pStream->State.cTransferTicks = ichac97R3StreamTransferCalcNext(pThis, pStream, pStream->State.cbTransferChunk); 2007 Assert(pStream->State.cTransferTicks); /* Paranoia. */ 2008 } 2009 2010 /** 1971 2011 * Opens an AC'97 stream with its current mixer settings. 1972 2012 * … … 1975 2015 * 1976 2016 * @returns IPRT status code. 1977 * @param pThis AC'97 state.1978 * @param pStream AC'97 Stream to open.2017 * @param pThis AC'97 device state. 2018 * @param pStream AC'97 stream to open. 1979 2019 */ 1980 2020 static int ichac97R3StreamOpen(PAC97STATE pThis, PAC97STREAM pStream) … … 2079 2119 rc = DrvAudioHlpStreamCfgCopy(&pStream->State.Cfg, &Cfg); 2080 2120 } 2081 2082 /*2083 * Set up data transfer stuff.2084 */2085 #ifdef LOG_ENABLED2086 ichac97R3BDLEDumpAll(pThis, pStream->Regs.bdbar, pStream->Regs.lvi + 1);2087 #endif2088 const uint32_t cbFrame = DrvAudioHlpPCMPropsBytesPerFrame(&Cfg.Props);2089 2090 /* Calculate the fragment size the guest OS expects interrupt delivery at. */2091 pStream->State.cbTransferSize = 441 * 4;//pStream->u32CBL / cFragments;2092 Assert(pStream->State.cbTransferSize);2093 Assert(pStream->State.cbTransferSize % cbFrame == 0);2094 2095 /* Calculate the bytes we need to transfer to / from the stream's DMA per iteration.2096 * This is bound to the device's Hz rate and thus to the (virtual) timing the device expects. */2097 pStream->State.cbTransferChunk = (pStream->State.Cfg.Props.uHz / pStream->State.uTimerHz) * cbFrame;2098 Assert(pStream->State.cbTransferChunk);2099 Assert(pStream->State.cbTransferChunk % cbFrame== 0);2100 2101 /* Make sure that the transfer chunk does not exceed the overall transfer size. */2102 if (pStream->State.cbTransferChunk > pStream->State.cbTransferSize)2103 pStream->State.cbTransferChunk = pStream->State.cbTransferSize;2104 2105 const uint64_t cTicksPerHz = TMTimerGetFreq((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD))/ pStream->State.uTimerHz;2106 2107 /* Calculate the timer ticks per byte for this stream. */2108 pStream->State.cTicksPerByte = cTicksPerHz / pStream->State.cbTransferChunk;2109 Assert(pStream->State.cTicksPerByte);2110 2111 /* Calculate timer ticks per transfer. */2112 pStream->State.cTransferTicks = pStream->State.cbTransferChunk * pStream->State.cTicksPerByte;2113 Assert(pStream->State.cTransferTicks);2114 2115 LogFunc(("[SD%RU8] Timer %uHz (%RU64 ticks per Hz), cTicksPerByte=%RU64, cbTransferChunk=%RU32, cTransferTicks=%RU64, " \2116 "cbTransferSize=%RU32\n",2117 pStream->u8SD, pStream->State.uTimerHz, cTicksPerHz, pStream->State.cTicksPerByte,2118 pStream->State.cbTransferChunk, pStream->State.cTransferTicks, pStream->State.cbTransferSize));2119 2120 2121 } 2121 2122 } … … 2656 2657 if (fSinkActive) 2657 2658 { 2658 TMTimerSet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD), 2659 TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks); 2659 ichac97R3StreamTransferUpdate(pThis, pStream, pStream->Regs.picb << 1); /** @todo r=andy Assumes 16-bit samples. */ 2660 2661 ichac97TimerSet(pThis,pStream, 2662 TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks, 2663 false /* fForce */); 2660 2664 } 2661 2665 … … 2664 2668 STAM_PROFILE_STOP(&pThis->StatTimer, a); 2665 2669 } 2670 #endif /* IN_RING3 */ 2666 2671 2667 2672 /** … … 2683 2688 * Forcing a new expiration time will override the above mechanism. 2684 2689 */ 2685 bool ichac97 R3TimerSet(PAC97STATE pThis, PAC97STREAM pStream, uint64_t tsExpire, bool fForce)2690 bool ichac97TimerSet(PAC97STATE pThis, PAC97STREAM pStream, uint64_t tsExpire, bool fForce) 2686 2691 { 2687 2692 AssertPtrReturn(pThis, false); … … 2705 2710 return RT_SUCCESS(rc); 2706 2711 } 2712 2713 #ifdef IN_RING3 2707 2714 2708 2715 /** … … 2724 2731 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 2725 2732 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 2726 AssertReturn(cbToProcessMax, VERR_INVALID_PARAMETER); 2733 2734 if (!cbToProcessMax) 2735 return VINF_SUCCESS; 2736 2737 #ifdef VBOX_STRICT 2738 const unsigned cbFrame = DrvAudioHlpPCMPropsBytesPerFrame(&pStream->State.Cfg.Props); 2739 #endif 2740 2741 /* Make sure to only process an integer number of audio frames. */ 2742 Assert(cbToProcessMax % cbFrame == 0); 2727 2743 2728 2744 ichac97R3StreamLock(pStream); … … 2770 2786 while (cbLeft) 2771 2787 { 2772 if (!pRegs->bd_valid)2773 {2774 Log3Func(("Invalid buffer descriptor, fetching next one ...\n"));2775 ichac97R3StreamFetchBDLE(pThis, pStream);2776 }2777 2778 2788 if (!pRegs->picb) /* Got a new buffer descriptor, that is, the position is 0? */ 2779 2789 { … … 2797 2807 } 2798 2808 2799 uint32_t cbChunk = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */ 2800 Assert(cbChunk); 2809 uint32_t cbChunk = cbLeft; 2801 2810 2802 2811 switch (pStream->u8SD) … … 3151 3160 pRegs->civ = pRegs->piv; 3152 3161 pRegs->piv = (pRegs->piv + 1) % AC97_MAX_BDLE; 3153 3154 ichac97R3StreamFetchBDLE(pThis, pStream);3155 3162 #else 3156 3163 rc = VINF_IOM_R3_IOPORT_WRITE; … … 3214 3221 3215 3222 /* Arm the timer for this stream. */ 3216 int rc2 = ichac97 R3TimerSet(pThis, pStream,3217 3218 3223 int rc2 = ichac97TimerSet(pThis, pStream, 3224 TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks, 3225 false /* fForce */); 3219 3226 AssertRC(rc2); 3220 3227 } … … 3778 3785 { 3779 3786 /* Re-arm the timer for this stream. */ 3780 rc2 = ichac97 R3TimerSet(pThis, pStream,3781 3782 3787 rc2 = ichac97TimerSet(pThis, pStream, 3788 TMTimerGet((pThis)->DEVAC97_CTX_SUFF_SD(pTimer, pStream->u8SD)) + pStream->State.cTransferTicks, 3789 false /* fForce */); 3783 3790 } 3784 3791
Note:
See TracChangeset
for help on using the changeset viewer.