Changeset 67416 in vbox for trunk/src/VBox/Devices/Audio
- Timestamp:
- Jun 15, 2017 9:04:51 AM (8 years ago)
- svn:sync-xref-src-repo-rev:
- 116142
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHDA.cpp
r67411 r67416 105 105 /** Default timer frequency (in Hz). */ 106 106 #define HDA_TIMER_HZ 200 107 108 /** HDA's (fixed) audio frame size in bytes. 109 * We only support 16-bit stereo frames at the moment. */ 110 #define HDA_FRAME_SIZE 4 107 111 108 112 /** … … 1013 1017 #ifdef IN_RING3 1014 1018 static void hdaStreamDestroy(PHDASTATE pThis, PHDASTREAM pStream); 1015 static int hdaStreamDoDMA(PHDASTATE pThis, PHDASTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t cbToProcess, uint32_t *pcbProcessed);1016 1019 static int hdaStreamEnable(PHDASTATE pThis, PHDASTREAM pStream, bool fEnable); 1017 static int hdaStreamUpdate(PHDASTATE pThis, PHDASTREAM pStream); 1020 uint32_t hdaStreamGetDataSize(PHDASTREAM pStream); 1021 static int hdaStreamTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcessMax); 1018 1022 DECLINLINE(uint32_t) hdaStreamUpdateLPIB(PHDASTATE pThis, PHDASTREAM pStream, uint32_t u32LPIB); 1019 1023 static void hdaStreamLock(PHDASTREAM pStream); … … 1379 1383 } 1380 1384 1381 1385 #if 0 1382 1386 /** 1383 1387 * Fetches the next BDLE to use for a stream. … … 1431 1435 return rc; 1432 1436 } 1437 #endif 1433 1438 1434 1439 … … 2067 2072 if (fEnable) 2068 2073 { 2074 /* (Re-)initialize the stream with current values. */ 2075 int rc2 = hdaStreamInit(pThis, pStream, pStream->u8SD); 2076 AssertRC(rc2); 2077 2069 2078 /* Begin a new period for this stream. */ 2070 intrc2 = hdaStreamPeriodBegin(&pStream->State.Period, hdaWalClkGetCurrent(pThis)/* Use current wall clock time */);2079 rc2 = hdaStreamPeriodBegin(&pStream->State.Period, hdaWalClkGetCurrent(pThis)/* Use current wall clock time */); 2071 2080 AssertRC(rc2); 2072 2081 } … … 2416 2425 /** 2417 2426 * Sets the actual WALCLK register to the specified wall clock value. 2418 * The specified wall clock value only will be set (unless fForce is set to \c @true) if all2427 * The specified wall clock value only will be set (unless fForce is set to true) if all 2419 2428 * handled HDA streams have passed (in time) that value. This guarantees that the WALCLK 2420 2429 * register stays in sync with all handled HDA streams. 2421 2430 * 2422 * @return \c @true if the WALCLK register has been updated, \c @false if not.2431 * @return true if the WALCLK register has been updated, false if not. 2423 2432 * @param pThis HDA state. 2424 2433 * @param u64WalClk Wall clock value to set WALCLK register to. … … 2721 2730 LogFunc(("[SD%RU8]: State changed (fRun=%RTbool)\n", pStream->u8SD, fRun)); 2722 2731 2723 if (fRun)2724 {2725 /* Make sure to first fetch the current BDLE before enabling the stream below. */2726 int rc2 = hdaBDLEFetch(pThis, &pStream->State.BDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);2727 AssertRC(rc2);2728 }2729 2730 2732 hdaStreamEnable(pThis, pStream, fRun /* fEnable */); 2731 2733 … … 2751 2753 { 2752 2754 #ifdef IN_RING3 2753 uint32_t v = HDA_REG_IND(pThis, iReg);2754 2755 2755 PHDASTREAM pStream = hdaStreamGetFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, STS, iReg)); 2756 2756 if (!pStream) … … 2761 2761 } 2762 2762 2763 uint32_t v = HDA_REG_IND(pThis, iReg); 2764 2763 2765 /* Clear (zero) FIFOE, DESE and BCIS bits when writing 1 to it (6.2.33). */ 2764 2766 HDA_REG_IND(pThis, iReg) &= ~(u32Value & v); … … 2766 2768 /* Some guests tend to write SDnSTS even if the stream is not running. 2767 2769 * So make sure to check if the RUN bit is set first. */ 2768 const bool fInRun = RT_BOOL(HDA_ REG_IND(pThis, iReg) & HDA_SDCTL_RUN);2770 const bool fInRun = RT_BOOL(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_SDCTL_RUN); 2769 2771 2770 2772 Log3Func(("[SD%RU8] fRun=%RTbool %R[sdsts]\n", pStream->u8SD, fInRun, v)); … … 3200 3202 { 3201 3203 #ifdef IN_RING3 3202 PDMAUDIOSTREAMCFG strmCfg;3203 RT_ZERO(strmCfg);3204 3205 int rc = hdaSDFMTToStrmCfg(u32Value, &strmCfg);3206 if (RT_FAILURE(rc))3207 return VINF_SUCCESS; /* Always return success to the MMIO handler. */3208 3209 3204 PHDASTREAM pStream = hdaStreamGetFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, FMT, iReg)); 3210 3205 if (!pStream) … … 3215 3210 } 3216 3211 3212 PPDMAUDIOSTREAMCFG pCfg = &pStream->State.strmCfg; 3213 3214 int rc = hdaSDFMTToStrmCfg(u32Value, pCfg); 3215 if (RT_FAILURE(rc)) 3216 return VINF_SUCCESS; /* Always return success to the MMIO handler. */ 3217 3217 3218 LogFunc(("[SD%RU8]: Hz=%RU32, Channels=%RU8, cBits=%RU8\n", 3218 pStream->u8SD, strmCfg.Props.uHz, strmCfg.Props.cChannels, strmCfg.Props.cBits));3219 pStream->u8SD, pCfg->Props.uHz, pCfg->Props.cChannels, pCfg->Props.cBits)); 3219 3220 3220 3221 /* Set audio direction. */ 3221 strmCfg.enmDir = hdaGetDirFromSD(pStream->u8SD);3222 switch ( strmCfg.enmDir)3222 pCfg->enmDir = hdaGetDirFromSD(pStream->u8SD); 3223 switch (pCfg->enmDir) 3223 3224 { 3224 3225 case PDMAUDIODIR_IN: … … 3226 3227 # error "Implement me!" 3227 3228 # else 3228 strmCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;3229 RTStrCopy( strmCfg.szName, sizeof(strmCfg.szName), "Line In");3229 pCfg->DestSource.Source = PDMAUDIORECSOURCE_LINE; 3230 RTStrCopy(pCfg->szName, sizeof(pCfg->szName), "Line In"); 3230 3231 # endif 3231 3232 break; … … 3254 3255 * the supported channels within a single audio stream, e.g. mono/stereo. 3255 3256 * 3256 * In other words, the stream mapping *always* know ns the real3257 * In other words, the stream mapping *always* knows the real 3257 3258 * number of channels in a single audio stream. 3258 3259 */ 3259 3260 if (RT_SUCCESS(rc)) 3260 3261 { 3261 rc = hdaStreamMapInit(&pStream->State.Mapping, &strmCfg);3262 rc = hdaStreamMapInit(&pStream->State.Mapping, pCfg); 3262 3263 AssertRC(rc); 3263 3264 } … … 3269 3270 { 3270 3271 int rc2; 3271 switch ( strmCfg.enmDir)3272 switch (pCfg->enmDir) 3272 3273 { 3273 3274 case PDMAUDIODIR_OUT: 3274 rc2 = hdaAddStreamOut(pThis, &strmCfg);3275 rc2 = hdaAddStreamOut(pThis, pCfg); 3275 3276 break; 3276 3277 3277 3278 case PDMAUDIODIR_IN: 3278 rc2 = hdaAddStreamIn(pThis, &strmCfg);3279 rc2 = hdaAddStreamIn(pThis, pCfg); 3279 3280 break; 3280 3281 … … 3503 3504 * Registers access handlers for a stream's BDLE DMA accesses. 3504 3505 * 3505 * @returns \c @true if registration was successful, \c @false if not.3506 * @returns true if registration was successful, false if not. 3506 3507 * @param pThis HDA state. 3507 3508 * @param pStream HDA stream to register BDLE access handlers for. … … 3707 3708 } 3708 3709 } 3709 #endif 3710 #endif /* LOG_ENABLED */ 3710 3711 3711 3712 /** … … 3743 3744 3744 3745 /** 3746 * Tells whether a given BDLE is complete or not. 3747 * 3748 * @return @true if BDLE is complete, @false if not. 3749 * @param pBDLE BDLE to retrieve status for. 3750 */ 3751 static bool hdaBDLEIsComplete(PHDABDLE pBDLE) 3752 { 3753 bool fIsComplete = false; 3754 3755 if ( !pBDLE->Desc.u32BufSize /* There can be BDLEs with 0 size. */ 3756 || (pBDLE->State.u32BufOff >= pBDLE->Desc.u32BufSize)) 3757 { 3758 Assert(pBDLE->State.u32BufOff == pBDLE->Desc.u32BufSize); 3759 fIsComplete = true; 3760 } 3761 3762 Log3Func(("%R[bdle] => %s\n", pBDLE, fIsComplete ? "COMPLETE" : "INCOMPLETE")); 3763 3764 return fIsComplete; 3765 } 3766 3767 /** 3768 * Tells whether a given BDLE needs an interrupt or not. 3769 * 3770 * @return @true if BDLE needs an interrupt, @false if not. 3771 * @param pBDLE BDLE to retrieve status for. 3772 */ 3773 static bool hdaBDLENeedsInterrupt(PHDABDLE pBDLE) 3774 { 3775 return (pBDLE->Desc.fFlags & HDA_BDLE_FLAG_IOC); 3776 } 3777 3778 /** 3745 3779 * Returns the number of outstanding stream data bytes which need to be processed 3746 3780 * by the DMA engine assigned to this stream. … … 3789 3823 } 3790 3824 3825 #if 0 3791 3826 DECLINLINE(void) hdaBDLEUpdate(PHDABDLE pBDLE, uint32_t cbData, uint32_t cbProcessed) 3792 3827 { … … 3824 3859 LogFlowFunc(("cbData=%RU32, cbProcessed=%RU32, %R[bdle]\n", cbData, cbProcessed, pBDLE)); 3825 3860 } 3861 #endif 3826 3862 3827 3863 #ifdef IN_RING3 … … 3934 3970 #endif /* IN_RING3 */ 3935 3971 3972 #if 0 3936 3973 DECLINLINE(bool) hdaStreamNeedsNextBDLE(PHDASTATE pThis, PHDASTREAM pStream) 3937 3974 { … … 3957 3994 3958 3995 return fNeedsNextBDLE; 3996 } 3997 #endif 3998 3999 /** 4000 * Returns the number of outstanding stream data bytes which need to be processed 4001 * by the DMA engine assigned to this stream. 4002 * 4003 * @return Number of bytes for the DMA engine to process. 4004 */ 4005 DECLINLINE(uint32_t) hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStream) 4006 { 4007 AssertPtrReturn(pThis, 0); 4008 AssertPtrReturn(pStream, 0); 4009 4010 if (!RT_BOOL(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_SDCTL_RUN)) 4011 { 4012 AssertFailed(); /* Should never happen. */ 4013 return 0; 4014 } 4015 4016 PHDABDLE pBDLE = &pStream->State.BDLE; 4017 4018 uint32_t cbFree = RT_MIN(pBDLE->Desc.u32BufSize, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff); 4019 4020 Log3Func(("[SD%RU8] LPIB=%RU32 CBL=%RU32 -> cbFree=%RU32 %R[bdle]\n", pStream->u8SD, 4021 HDA_STREAM_REG(pThis, LPIB, pStream->u8SD), pStream->u32CBL, cbFree, pBDLE)); 4022 return cbFree; 4023 } 4024 4025 DECLINLINE(void) hdaStreamTransferInc(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbInc) 4026 { 4027 AssertPtrReturnVoid(pThis); 4028 AssertPtrReturnVoid(pStream); 4029 4030 if (!cbInc) 4031 return; 4032 4033 const uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStream->u8SD); 4034 4035 Log3Func(("[SD%RU8] %RU32 + %RU32 -> %RU32, CBL=%RU32\n", 4036 pStream->u8SD, u32LPIB, cbInc, u32LPIB + cbInc, pStream->u32CBL)); 4037 4038 hdaStreamUpdateLPIB(pThis, pStream, u32LPIB + cbInc); 3959 4039 } 3960 4040 … … 3984 4064 } 3985 4065 4066 #if 0 3986 4067 static bool hdaBDLEIsComplete(PHDABDLE pBDLE, bool *pfInterrupt) 3987 4068 { … … 4015 4096 return fIsComplete; 4016 4097 } 4098 #endif 4017 4099 4018 4100 /** … … 4633 4715 4634 4716 /** 4717 * Reads DMA data from a given HDA output stream into its associated FIFO buffer. 4718 * 4719 * @return IPRT status code. 4720 * @param pThis HDA state. 4721 * @param pStream HDA output stream to read DMA data from. 4722 * @param cbToRead How much (in bytes) to read from DMA. 4723 * @param pcbRead Returns read bytes from DMA. Optional. 4724 */ 4725 static int hdaDMARead(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead) 4726 { 4727 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 4728 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 4729 /* pcbRead is optional. */ 4730 4731 int rc = VINF_SUCCESS; 4732 4733 uint32_t cbReadTotal = 0; 4734 4735 PHDABDLE pBDLE = &pStream->State.BDLE; 4736 PRTCIRCBUF pCircBuf = pStream->State.pCircBuf; 4737 AssertPtr(pCircBuf); 4738 4739 #ifdef HDA_DEBUG_SILENCE 4740 uint64_t csSilence = 0; 4741 4742 pStream->Dbg.cSilenceThreshold = 100; 4743 pStream->Dbg.cbSilenceReadMin = _1M; 4744 #endif 4745 4746 while (cbToRead) 4747 { 4748 /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */ 4749 void *pvBuf; 4750 size_t cbBuf; 4751 RTCircBufAcquireWriteBlock(pCircBuf, RT_MIN(cbToRead, pStream->u16FIFOS), &pvBuf, &cbBuf); 4752 4753 if (cbBuf) 4754 { 4755 /* 4756 * Read from the current BDLE's DMA buffer. 4757 */ 4758 int rc2 = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), 4759 pBDLE->Desc.u64BufAdr + pBDLE->State.u32BufOff + cbReadTotal, pvBuf, cbBuf); 4760 AssertRC(rc2); 4761 4762 #ifdef HDA_DEBUG_SILENCE 4763 uint16_t *pu16Buf = (uint16_t *)pvBuf; 4764 for (size_t i = 0; i < cbBuf / sizeof(uint16_t); i++) 4765 { 4766 if (*pu16Buf == 0) 4767 { 4768 csSilence++; 4769 } 4770 else 4771 break; 4772 pu16Buf++; 4773 } 4774 #endif 4775 4776 #ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA 4777 if (cbBuf) 4778 { 4779 RTFILE fh; 4780 rc2 = RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaDMARead.pcm", 4781 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 4782 if (RT_SUCCESS(rc2)) 4783 { 4784 RTFileWrite(fh, pvBuf, cbBuf, NULL); 4785 RTFileClose(fh); 4786 } 4787 else 4788 AssertRC(rc2); 4789 } 4790 #endif 4791 4792 #if 0 4793 pStream->Dbg.cbReadTotal += cbBuf; 4794 const uint64_t cbWritten = ASMAtomicReadU64(&pStream->Dbg.cbWrittenTotal); 4795 Log3Func(("cbRead=%RU64, cbWritten=%RU64 -> %RU64 bytes %s\n", 4796 pStream->Dbg.cbReadTotal, cbWritten, 4797 pStream->Dbg.cbReadTotal >= cbWritten ? pStream->Dbg.cbReadTotal - cbWritten : cbWritten - pStream->Dbg.cbReadTotal, 4798 pStream->Dbg.cbReadTotal > cbWritten ? "too much" : "too little")); 4799 #endif 4800 4801 #ifdef VBOX_WITH_STATISTICS 4802 STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBuf); 4803 #endif 4804 } 4805 4806 RTCircBufReleaseWriteBlock(pCircBuf, cbBuf); 4807 4808 if (!cbBuf) 4809 { 4810 rc = VERR_BUFFER_OVERFLOW; 4811 break; 4812 } 4813 4814 cbReadTotal += (uint32_t)cbBuf; 4815 Assert(pBDLE->State.u32BufOff + cbReadTotal <= pBDLE->Desc.u32BufSize); 4816 4817 Assert(cbToRead >= cbBuf); 4818 cbToRead -= (uint32_t)cbBuf; 4819 } 4820 4821 #ifdef HDA_DEBUG_SILENCE 4822 4823 if (csSilence) 4824 pStream->Dbg.csSilence += csSilence; 4825 4826 if ( csSilence == 0 4827 && pStream->Dbg.csSilence > pStream->Dbg.cSilenceThreshold 4828 && pStream->Dbg.cbReadTotal >= pStream->Dbg.cbSilenceReadMin) 4829 { 4830 LogFunc(("Silent block detected: %RU64 audio samples\n", pStream->Dbg.csSilence)); 4831 pStream->Dbg.csSilence = 0; 4832 } 4833 #endif 4834 4835 if (RT_SUCCESS(rc)) 4836 { 4837 if (pcbRead) 4838 *pcbRead = cbReadTotal; 4839 } 4840 4841 return rc; 4842 } 4843 4844 /** 4845 * Writes audio data from an HDA input stream's FIFO to its associated DMA area. 4846 * 4847 * @return IPRT status code. 4848 * @param pThis HDA state. 4849 * @param pStream HDA input stream to write audio data to. 4850 * @param cbToWrite How much (in bytes) to write. 4851 * @param pcbWritten Returns written bytes on success. Optional. 4852 */ 4853 static int hdaDMAWrite(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten) 4854 { 4855 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 4856 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 4857 /* pcbWritten is optional. */ 4858 4859 PHDABDLE pBDLE = &pStream->State.BDLE; 4860 PRTCIRCBUF pCircBuf = pStream->State.pCircBuf; 4861 AssertPtr(pCircBuf); 4862 4863 int rc = VINF_SUCCESS; 4864 4865 uint32_t cbWrittenTotal = 0; 4866 4867 void *pvBuf = NULL; 4868 size_t cbBuf = 0; 4869 4870 uint8_t abSilence[HDA_FIFO_MAX + 1] = { 0 }; 4871 4872 while (cbToWrite) 4873 { 4874 size_t cbChunk = RT_MIN(cbToWrite, pStream->u16FIFOS); 4875 4876 size_t cbBlock = 0; 4877 RTCircBufAcquireReadBlock(pCircBuf, cbChunk, &pvBuf, &cbBlock); 4878 4879 if (cbBlock) 4880 { 4881 cbBuf = cbBlock; 4882 } 4883 else /* No audio data available? Send silence. */ 4884 { 4885 pvBuf = &abSilence; 4886 cbBuf = cbChunk; 4887 } 4888 4889 /* Sanity checks. */ 4890 Assert(cbBuf <= pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff); 4891 Assert(cbBuf % HDA_FRAME_SIZE == 0); 4892 Assert((cbBuf >> 1) >= 1); 4893 4894 #ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA 4895 RTFILE fh; 4896 RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "hdaDMAWrite.pcm", 4897 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 4898 RTFileWrite(fh, pvBuf, cbBuf, NULL); 4899 RTFileClose(fh); 4900 #endif 4901 int rc2 = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), 4902 pBDLE->Desc.u64BufAdr + pBDLE->State.u32BufOff + cbWrittenTotal, 4903 pvBuf, cbBuf); 4904 AssertRC(rc2); 4905 4906 #ifdef VBOX_WITH_STATISTICS 4907 STAM_COUNTER_ADD(&pThis->StatBytesWritten, cbBuf); 4908 #endif 4909 if (cbBlock) 4910 RTCircBufReleaseReadBlock(pCircBuf, cbBlock); 4911 4912 Assert(cbToWrite >= cbBuf); 4913 cbToWrite -= (uint32_t)cbBuf; 4914 4915 cbWrittenTotal += (uint32_t)cbBuf; 4916 } 4917 4918 if (RT_SUCCESS(rc)) 4919 { 4920 if (pcbWritten) 4921 *pcbWritten = cbWrittenTotal; 4922 } 4923 else 4924 LogFunc(("Failed with %Rrc\n", rc)); 4925 4926 return rc; 4927 } 4928 4929 /** 4635 4930 * Timer callback which handles the audio data transfers on a periodic basis. 4636 4931 * … … 4708 5003 static void hdaDoTransfers(PHDASTATE pThis) 4709 5004 { 4710 PHDASTREAM pStreamLineIn = hdaSinkGetStream(pThis, &pThis->SinkLineIn);5005 //PHDASTREAM pStreamLineIn = hdaSinkGetStream(pThis, &pThis->SinkLineIn); 4711 5006 #ifdef VBOX_WITH_AUDIO_HDA_MIC_IN 4712 5007 PHDASTREAM pStreamMicIn = hdaSinkGetStream(pThis, &pThis->SinkMicIn); … … 4717 5012 #endif 4718 5013 4719 hdaStreamUpdate(pThis, pStreamLineIn); 5014 #if 0 5015 uint32_t cbWritten = 0; 5016 int rc2 = hdaStreamWrite(pThis, pStreamLineIn, &cbWritten); 5017 if ( RT_SUCCESS(rc2) 5018 && cbWritten) 5019 { 5020 rc2 = hdaStreamTransfer(pThis, pStreamLineIn, cbWritten); 5021 AssertRC(rc2); 5022 } 5023 4720 5024 #ifdef VBOX_WITH_AUDIO_HDA_MIC_IN 4721 hdaStreamUpdate(pThis, pStreamMicIn); 4722 #endif 4723 hdaStreamUpdate(pThis, pStreamFront); 4724 5025 rc2 = hdaStreamWrite(pThis, pStreamMicIn, &cbWritten); 5026 if ( RT_SUCCESS(rc2) 5027 && cbWritten) 5028 { 5029 rc2 = hdaStreamTransfer(pThis, pStreamMicIn, cbWritten); 5030 AssertRC(rc2); 5031 } 5032 #endif 5033 #endif 5034 5035 int rc2; 5036 5037 /* Is the sink ready to be written to? If so, how much? */ 5038 uint32_t cbToWrite = AudioMixerSinkGetWritable(pThis->SinkFront.pMixSink); 5039 if (cbToWrite) 5040 { 5041 rc2 = hdaStreamTransfer(pThis, pStreamFront, cbToWrite); 5042 AssertRC(rc2); 5043 5044 if (hdaStreamGetDataSize(pStreamFront)) 5045 { 5046 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 5047 /* Let the asynchronous thread know that there is some new data to process. */ 5048 hdaStreamAsyncIONotify(pThis, pStreamFront); 5049 #else 5050 /* Read audio data from the HDA stream and write to the backends. */ 5051 rc2 = hdaStreamRead(pThis, pStream, cbToWrite, NULL /* pcbRead */); 5052 AssertRC(rc2); 5053 #endif 5054 } 5055 } 4725 5056 4726 5057 #ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND 4727 intrc2 = AudioMixerSinkUpdate(pThis->SinkCenterLFE.pMixSink);5058 rc2 = AudioMixerSinkUpdate(pThis->SinkCenterLFE.pMixSink); 4728 5059 AssertRC(rc2); 4729 5060 … … 4744 5075 #endif 4745 5076 5077 #if 0 4746 5078 /** 4747 5079 * Does a single DMA transfer for a specific HDA stream (SDI/SDO). … … 4940 5272 return rc; 4941 5273 } 5274 #endif 5275 5276 /** 5277 * Retrieves the available size of (buffered) audio data (in bytes) of a given HDA stream. 5278 * 5279 * @returns Data size (in bytes). 5280 * @param pStream HDA stream to retrieve size for. 5281 */ 5282 uint32_t hdaStreamGetDataSize(PHDASTREAM pStream) 5283 { 5284 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 5285 5286 if (!pStream->State.pCircBuf) 5287 return 0; 5288 5289 return (uint32_t)RTCircBufSize(pStream->State.pCircBuf); 5290 } 4942 5291 4943 5292 /** … … 5293 5642 #endif /* VBOX_WITH_AUDIO_HDA_ASYNC_IO */ 5294 5643 5295 /** 5296 * Updates a HDA stream according to its usage (input / output). 5644 static uint32_t hdaStreamTransferGetElapsed(PHDASTATE pThis, PHDASTREAM pStream) 5645 { 5646 const uint64_t cTicksNow = TMTimerGet(pThis->pTimer); 5647 const uint64_t cTicksPerSec = TMTimerGetFreq(pThis->pTimer); 5648 5649 const uint64_t cTicksElapsed = cTicksNow - pStream->State.uTimerTS; 5650 #ifdef DEBUG 5651 const uint64_t cMsElapsed = cTicksElapsed / (cTicksPerSec / 1000); 5652 #endif 5653 5654 AssertPtr(pThis->pCodec); 5655 5656 PPDMAUDIOSTREAMCFG pCfg = &pStream->State.strmCfg; 5657 5658 /* A stream *always* runs with 48 kHz device-wise, regardless of the actual stream input/output format (Hz) being set. */ 5659 uint32_t csPerPeriod = (int)((pCfg->Props.cChannels * cTicksElapsed * 48000 /* Hz */ + cTicksPerSec) / cTicksPerSec / 2); 5660 uint32_t cbPerPeriod = csPerPeriod << pCfg->Props.cShift; 5661 5662 Log3Func(("[SD%RU8] %RU64ms (%zu samples, %zu bytes) elapsed\n", pStream->u8SD, cMsElapsed, csPerPeriod, cbPerPeriod)); 5663 5664 return cbPerPeriod; 5665 } 5666 5667 /** 5668 * Transfers data of an HDA stream according to its usage (input / output). 5297 5669 * 5298 5670 * For an SDO (output) stream this means reading DMA data from the device to 5299 * the connected audio sink(s).5300 * 5301 * For an SDI (input) stream this is reading audio data from the connected5302 * audio sink(s)and writing it as DMA data to the device.5671 * the HDA stream's internal FIFO buffer. 5672 * 5673 * For an SDI (input) stream this is reading audio data from the HDA stream's 5674 * internal FIFO buffer and writing it as DMA data to the device. 5303 5675 * 5304 5676 * @returns IPRT status code. 5305 5677 * @param pThis HDA state. 5306 5678 * @param pStream HDA stream to update. 5307 */ 5308 static int hdaStreamUpdate(PHDASTATE pThis, PHDASTREAM pStream) 5309 { 5310 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 5311 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 5679 * @param cbToProcessMax Maximum of data (in bytes) to process. 5680 */ 5681 static int hdaStreamTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcessMax) 5682 { 5683 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 5684 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 5685 AssertReturn(cbToProcessMax, VERR_INVALID_PARAMETER); 5312 5686 5313 5687 hdaStreamLock(pStream); 5314 5688 5315 PHDAMIXERSINK pSink = pStream->pMixSink; 5316 AssertPtr(pSink); 5317 5318 PRTCIRCBUF pCircBuf = pStream->State.pCircBuf; 5319 AssertPtr(pCircBuf); 5320 5321 if (!AudioMixerSinkIsActive(pSink->pMixSink)) 5322 { 5689 PHDASTREAMPERIOD pPeriod = &pStream->State.Period; 5690 int rc = hdaStreamPeriodLock(pPeriod); 5691 AssertRC(rc); 5692 5693 bool fProceed = true; 5694 5695 /* Stream not running? */ 5696 if (!(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_SDCTL_RUN)) 5697 { 5698 Log3Func(("[SD%RU8] RUN bit not set\n", pStream->u8SD)); 5699 fProceed = false; 5700 } 5701 /* Period complete? */ 5702 else if (hdaStreamPeriodIsComplete(pPeriod)) 5703 { 5704 Log3Func(("[SD%RU8] Period is complete, nothing to do\n", pStream->u8SD)); 5705 fProceed = false; 5706 } 5707 5708 if (!fProceed) 5709 { 5710 hdaStreamPeriodUnlock(pPeriod); 5323 5711 hdaStreamUnlock(pStream); 5324 5712 return VINF_SUCCESS; 5325 5713 } 5326 5714 5715 /* Sanity checks. */ 5716 Assert(pStream->u8SD <= HDA_MAX_STREAMS); 5717 Assert(pStream->u64BDLBase); 5718 5719 /* State sanity checks. */ 5720 Assert(ASMAtomicReadBool(&pStream->State.fInReset) == false); 5721 5722 /* Fetch first / next BDL entry. */ 5723 PHDABDLE pBDLE = &pStream->State.BDLE; 5724 if (hdaBDLEIsComplete(pBDLE)) 5725 { 5726 rc = hdaBDLEFetch(pThis, pBDLE, pStream->u64BDLBase, pStream->State.uCurBDLE); 5727 AssertRC(rc); 5728 } 5729 5730 const uint32_t cbPeriodRemaining = hdaStreamPeriodGetRemainingFrames(pPeriod) * HDA_FRAME_SIZE; 5731 Assert(cbPeriodRemaining); /* Paranoia. */ 5732 5733 const uint32_t cbElapsed = hdaStreamTransferGetElapsed(pThis, pStream); 5734 5735 /* Limit the data to read, as this routine could be delayed and therefore 5736 * report wrong (e.g. too much) cbElapsed bytes. */ 5737 uint32_t cbLeft = RT_MIN(RT_MIN(cbPeriodRemaining, cbElapsed), cbToProcessMax); 5738 Assert(cbLeft % HDA_FRAME_SIZE == 0); /* Paranoia. */ 5739 5740 Log3Func(("[SD%RU8] cbPeriodRemaining=%RU32, cbElapsed=%RU32, cbToProcessMax=%RU32 -> cbLeft=%RU32\n", 5741 pStream->u8SD, cbPeriodRemaining, cbElapsed, cbToProcessMax, cbLeft)); 5742 5327 5743 Log2Func(("[SD%RU8]\n", pStream->u8SD)); 5328 5744 5329 bool fDone = false; 5330 uint8_t cTransfers = 0; 5331 5332 while (!fDone) 5333 { 5334 int rc2; 5335 uint32_t cbDMA = 0; 5336 5745 while (cbLeft >> 1) /** @todo Define frame size? */ 5746 { 5747 uint32_t cbChunk = RT_MIN(hdaStreamGetTransferSize(pThis, pStream), cbLeft); 5748 uint32_t cbDMA = 0; 5749 #if 1 5750 if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */ 5751 { 5752 STAM_PROFILE_START(&pThis->StatOut, a); 5753 5754 rc = hdaDMARead(pThis, pStream, cbChunk, &cbDMA /* pcbRead */); 5755 if (RT_FAILURE(rc)) 5756 LogRel(("HDA: Reading from stream #%RU8 DMA failed with %Rrc\n", pStream->u8SD, rc)); 5757 5758 STAM_PROFILE_STOP(&pThis->StatOut, a); 5759 } 5760 else if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN) /* Input (SDI). */ 5761 { 5762 STAM_PROFILE_START(&pThis->StatIn, a); 5763 5764 rc = hdaDMAWrite(pThis, pStream, cbChunk, &cbDMA /* pcbWritten */); 5765 if (RT_FAILURE(rc)) 5766 LogRel(("HDA: Writing to stream #%RU8 DMA failed with %Rrc\n", pStream->u8SD, rc)); 5767 5768 STAM_PROFILE_STOP(&pThis->StatIn, a); 5769 } 5770 else /** @todo Handle duplex streams? */ 5771 AssertFailed(); 5772 5773 if (cbDMA) 5774 { 5775 Assert(cbDMA % HDA_FRAME_SIZE == 0); 5776 5777 /* We always increment the position of DMA buffer counter because we're always reading 5778 * into an intermediate buffer. */ 5779 pBDLE->State.u32BufOff += (uint32_t)cbDMA; 5780 Assert(pBDLE->State.u32BufOff <= pBDLE->Desc.u32BufSize); 5781 5782 hdaStreamTransferInc(pThis, pStream, cbDMA); 5783 5784 uint32_t framesDMA = cbDMA / 4; /** @todo Define frame size? */ 5785 5786 /* Add the transferred frames to the period. */ 5787 hdaStreamPeriodInc(pPeriod, framesDMA); 5788 5789 /* Save the timestamp of when the last successful DMA transfer has been for this stream. */ 5790 pStream->State.uTimerTS = TMTimerGet(pThis->pTimer); 5791 5792 Assert(cbLeft >= cbDMA); 5793 cbLeft -= cbDMA; 5794 } 5795 5796 if (hdaBDLEIsComplete(pBDLE)) 5797 { 5798 Log3Func(("[SD%RU8] Complete: %R[bdle]\n", pStream->u8SD, pBDLE)); 5799 5800 if (hdaBDLENeedsInterrupt(pBDLE)) 5801 { 5802 /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL register is set 5803 * we need to generate an interrupt. 5804 */ 5805 if (HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_SDCTL_IOCE) 5806 hdaStreamPeriodAcquireInterrupt(pPeriod); 5807 } 5808 5809 if (pStream->State.uCurBDLE == pStream->u16LVI) 5810 { 5811 Assert(pStream->u32CBL == HDA_STREAM_REG(pThis, LPIB, pStream->u8SD)); 5812 5813 pStream->State.uCurBDLE = 0; 5814 hdaStreamUpdateLPIB(pThis, pStream, 0 /* LPIB */); 5815 } 5816 else 5817 pStream->State.uCurBDLE++; 5818 5819 hdaBDLEFetch(pThis, pBDLE, pStream->u64BDLBase, pStream->State.uCurBDLE); 5820 5821 Log3Func(("[SD%RU8] Fetching: %R[bdle]\n", pStream->u8SD, pBDLE)); 5822 } 5823 5824 if (RT_FAILURE(rc)) 5825 break; 5826 } 5827 5828 if (hdaStreamPeriodIsComplete(pPeriod)) 5829 { 5830 Log3Func(("[SD%RU8] Period complete -- Current: %R[bdle]\n", pStream->u8SD, &pStream->State.BDLE)); 5831 5832 /* Set the stream's BCIS bit. 5833 * 5834 * Note: This only must be done if the whole period is complete, and not if only 5835 * one specific BDL entry is complete (if it has the IOC bit set). 5836 * 5837 * This will otherwise confuses the guest when it 1) deasserts the interrupt, 5838 * 2) reads SDSTS (with BCIS set) and then 3) too early reads a (wrong) WALCLK value. 5839 * 5840 * snd_hda_intel on Linux will tell. */ 5841 HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_SDSTS_BCIS; 5842 5843 /* Try updating the wall clock. */ 5844 const uint64_t u64WalClk = hdaStreamPeriodGetAbsElapsedWalClk(pPeriod); 5845 const bool fWalClkSet = hdaWalClkSet(pThis, u64WalClk, false /* fForce */); 5846 5847 /* Does the period have any interrupts outstanding? */ 5848 if (hdaStreamPeriodNeedsInterrupt(pPeriod)) 5849 { 5850 if (fWalClkSet) 5851 { 5852 Log3Func(("[SD%RU8] Set WALCLK to %RU64, triggering interrupt\n", pStream->u8SD, u64WalClk)); 5853 5854 /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with 5855 * ending / beginning a period. */ 5856 #ifndef DEBUG 5857 hdaProcessInterrupt(pThis); 5858 #else 5859 hdaProcessInterrupt(pThis, __FUNCTION__); 5860 #endif 5861 } 5862 } 5863 else 5864 { 5865 /* End the period first ... */ 5866 hdaStreamPeriodEnd(pPeriod); 5867 5868 /* ... and immediately begin the next one. */ 5869 hdaStreamPeriodBegin(pPeriod, hdaWalClkGetCurrent(pThis)); 5870 } 5871 } 5872 5873 hdaStreamPeriodUnlock(pPeriod); 5874 #else 5337 5875 if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */ 5338 5876 { … … 5459 5997 if (++cTransfers == UINT8_MAX) /* Failsafe counter. */ 5460 5998 fDone = true; 5461 5462 5999 } /* while !fDone */ 5463 6000 5464 6001 #ifdef VBOX_STRICT 5465 6002 AssertMsg(cTransfers < UINT8_MAX, ("HDA: Update for SD#%RU8 ran for too long\n", pStream->u8SD)); 6003 #endif 5466 6004 #endif 5467 6005
Note:
See TracChangeset
for help on using the changeset viewer.