Changeset 89721 in vbox
- Timestamp:
- Jun 15, 2021 7:03:40 PM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
r89715 r89721 679 679 * Internal Functions * 680 680 *********************************************************************************************************************************/ 681 static void ichac97StreamUpdateSR(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, uint32_t new_sr); 682 static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t uMixerIdx); 681 683 #ifdef IN_RING3 682 static int ichac97R3StreamOpen(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC, PAC97STREAM pStream, 683 PAC97STREAMR3 pStreamCC, bool fForce); 684 static int ichac97R3StreamClose(PAC97STREAM pStream); 685 static void ichac97R3StreamLock(PAC97STREAMR3 pStreamCC); 686 static void ichac97R3StreamUnlock(PAC97STREAMR3 pStreamCC); 687 static uint32_t ichac97R3StreamGetUsed(PAC97STREAMR3 pStreamCC); 688 static uint32_t ichac97R3StreamGetFree(PAC97STREAMR3 pStreamCC); 689 static int ichac97R3StreamTransfer(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, 690 PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax, 691 bool fWriteSilence, bool fInput); 692 static DECLCALLBACK(void) ichac97R3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser); 693 694 static DECLCALLBACK(void) ichac97R3Reset(PPDMDEVINS pDevIns); 695 696 static void ichac97R3MixerRemoveDrvStreams(PPDMDEVINS pDevIns, PAC97STATER3 pThisCC, PAUDMIXSINK pMixSink, 697 PDMAUDIODIR enmDir, PDMAUDIOPATH enmPath); 698 699 DECLINLINE(PDMAUDIODIR) ichac97GetDirFromSD(uint8_t uSD); 700 DECLINLINE(void) ichac97R3TimerSet(PPDMDEVINS pDevIns, PAC97STREAM pStream, uint64_t cTicksToDeadline); 701 702 static void ichac97R3DbgPrintBdl(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, 703 PCDBGFINFOHLP pHlp, const char *pszPrefix); 704 #endif /* IN_RING3 */ 684 static void ichac97R3StreamLock(PAC97STREAMR3 pStreamCC); 685 static void ichac97R3StreamUnlock(PAC97STREAMR3 pStreamCC); 686 687 static void ichac97R3DbgPrintBdl(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, 688 PCDBGFINFOHLP pHlp, const char *pszPrefix); 689 static DECLCALLBACK(void) ichac97R3Reset(PPDMDEVINS pDevIns); 690 #endif 705 691 706 692 … … 814 800 815 801 /** 802 * Returns the audio direction of a specified stream descriptor. 803 * 804 * @return Audio direction. 805 */ 806 DECLINLINE(PDMAUDIODIR) ichac97R3GetDirFromSD(uint8_t uSD) 807 { 808 switch (uSD) 809 { 810 case AC97SOUNDSOURCE_PI_INDEX: return PDMAUDIODIR_IN; 811 case AC97SOUNDSOURCE_PO_INDEX: return PDMAUDIODIR_OUT; 812 case AC97SOUNDSOURCE_MC_INDEX: return PDMAUDIODIR_IN; 813 } 814 815 AssertFailed(); 816 return PDMAUDIODIR_UNKNOWN; 817 } 818 819 820 /** 816 821 * Retrieves the audio mixer sink of a corresponding AC'97 stream index. 817 822 * … … 831 836 } 832 837 } 838 839 840 /********************************************************************************************************************************* 841 * Stream DMA * 842 *********************************************************************************************************************************/ 843 844 /** 845 * Retrieves the available size of (buffered) audio data (in bytes) of a given AC'97 stream. 846 * 847 * @returns Available data (in bytes). 848 * @param pStreamCC The AC'97 stream to retrieve size for (ring-3). 849 */ 850 static uint32_t ichac97R3StreamGetUsed(PAC97STREAMR3 pStreamCC) 851 { 852 if (!pStreamCC->State.pCircBuf) 853 return 0; 854 855 return (uint32_t)RTCircBufUsed(pStreamCC->State.pCircBuf); 856 } 857 858 /** 859 * Retrieves the free size of audio data (in bytes) of a given AC'97 stream. 860 * 861 * @returns Free data (in bytes). 862 * @param pStreamCC AC'97 stream to retrieve size for (ring-3). 863 */ 864 static uint32_t ichac97R3StreamGetFree(PAC97STREAMR3 pStreamCC) 865 { 866 if (!pStreamCC->State.pCircBuf) 867 return 0; 868 869 return (uint32_t)RTCircBufFree(pStreamCC->State.pCircBuf); 870 } 871 872 # if 0 /* Unused */ 873 static void ichac97R3WriteBUP(PAC97STATE pThis, uint32_t cbElapsed) 874 { 875 LogFlowFunc(("cbElapsed=%RU32\n", cbElapsed)); 876 877 if (!(pThis->bup_flag & BUP_SET)) 878 { 879 if (pThis->bup_flag & BUP_LAST) 880 { 881 unsigned int i; 882 uint32_t *p = (uint32_t*)pThis->silence; 883 for (i = 0; i < sizeof(pThis->silence) / 4; i++) /** @todo r=andy Assumes 16-bit samples, stereo. */ 884 *p++ = pThis->last_samp; 885 } 886 else 887 RT_ZERO(pThis->silence); 888 889 pThis->bup_flag |= BUP_SET; 890 } 891 892 while (cbElapsed) 893 { 894 uint32_t cbToWrite = RT_MIN(cbElapsed, (uint32_t)sizeof(pThis->silence)); 895 uint32_t cbWrittenToStream; 896 897 int rc2 = AudioMixerSinkWrite(pThisCC->pSinkOut, AUDMIXOP_COPY, 898 pThis->silence, cbToWrite, &cbWrittenToStream); 899 if (RT_SUCCESS(rc2)) 900 { 901 if (cbWrittenToStream < cbToWrite) /* Lagging behind? */ 902 LogFlowFunc(("Warning: Only written %RU32 / %RU32 bytes, expect lags\n", cbWrittenToStream, cbToWrite)); 903 } 904 905 /* Always report all data as being written; 906 * backends who were not able to catch up have to deal with it themselves. */ 907 Assert(cbElapsed >= cbToWrite); 908 cbElapsed -= cbToWrite; 909 } 910 } 911 # endif /* Unused */ 912 833 913 834 914 /** … … 911 991 } 912 992 913 #endif /* IN_RING3 */ 914 915 /** 916 * Updates the status register (SR) of an AC'97 audio stream. 917 * 993 994 /** 995 * Transfers data of an AC'97 stream according to its usage (input / output). 996 * 997 * For an SDO (output) stream this means reading DMA data from the device to 998 * the AC'97 stream's internal FIFO buffer. 999 * 1000 * For an SDI (input) stream this is reading audio data from the AC'97 stream's 1001 * internal FIFO buffer and writing it as DMA data to the device. 1002 * 1003 * @returns VBox status code. 918 1004 * @param pDevIns The device instance. 919 1005 * @param pThis The shared AC'97 state. 920 * @param pStream AC'97 stream to update SR for. 921 * @param new_sr New value for status register (SR). 922 */ 923 static void ichac97StreamUpdateSR(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, uint32_t new_sr) 924 { 925 PAC97BMREGS pRegs = &pStream->Regs; 926 927 bool fSignal = false; 928 int iIRQL = 0; 929 930 uint32_t new_mask = new_sr & AC97_SR_INT_MASK; 931 uint32_t old_mask = pRegs->sr & AC97_SR_INT_MASK; 932 933 if (new_mask ^ old_mask) 934 { 935 /** @todo Is IRQ deasserted when only one of status bits is cleared? */ 936 if (!new_mask) 1006 * @param pStream The AC'97 stream to update (shared). 1007 * @param pStreamCC The AC'97 stream to update (ring-3). 1008 * @param cbToProcessMax Maximum of data (in bytes) to process. 1009 * @param fWriteSilence Whether to write silence if this is an input 1010 * stream (done while waiting for backend to get 1011 * going). 1012 * @param fInput Set if input, clear if output. 1013 */ 1014 static int ichac97R3StreamTransfer(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, 1015 PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax, bool fWriteSilence, bool fInput) 1016 { 1017 if (!cbToProcessMax) 1018 return VINF_SUCCESS; 1019 1020 #ifdef VBOX_STRICT 1021 const unsigned cbFrame = PDMAudioPropsBytesPerFrame(&pStreamCC->State.Cfg.Props); 1022 #endif 1023 1024 /* Make sure to only process an integer number of audio frames. */ 1025 Assert(cbToProcessMax % cbFrame == 0); 1026 1027 ichac97R3StreamLock(pStreamCC); 1028 1029 PAC97BMREGS pRegs = &pStream->Regs; 1030 1031 if (pRegs->sr & AC97_SR_DCH) /* Controller halted? */ 1032 { 1033 if (pRegs->cr & AC97_CR_RPBM) /* Bus master operation starts. */ 937 1034 { 938 fSignal = true; 939 iIRQL = 0; 1035 switch (pStream->u8SD) 1036 { 1037 case AC97SOUNDSOURCE_PO_INDEX: 1038 /*ichac97R3WriteBUP(pThis, cbToProcess);*/ 1039 break; 1040 1041 default: 1042 break; 1043 } 940 1044 } 941 else if ((new_mask & AC97_SR_LVBCI) && (pRegs->cr & AC97_CR_LVBIE)) 1045 1046 ichac97R3StreamUnlock(pStreamCC); 1047 return VINF_SUCCESS; 1048 } 1049 1050 /* BCIS flag still set? Skip iteration. */ 1051 if (pRegs->sr & AC97_SR_BCIS) 1052 { 1053 Log3Func(("[SD%RU8] BCIS set\n", pStream->u8SD)); 1054 1055 ichac97R3StreamUnlock(pStreamCC); 1056 return VINF_SUCCESS; 1057 } 1058 1059 uint32_t cbLeft = RT_MIN((uint32_t)(pRegs->picb << 1), cbToProcessMax); /** @todo r=andy Assumes 16bit samples. */ 1060 uint32_t cbProcessedTotal = 0; 1061 1062 PRTCIRCBUF pCircBuf = pStreamCC->State.pCircBuf; 1063 AssertPtr(pCircBuf); 1064 1065 int rc = VINF_SUCCESS; 1066 1067 Log3Func(("[SD%RU8] cbToProcessMax=%RU32, cbLeft=%RU32\n", pStream->u8SD, cbToProcessMax, cbLeft)); 1068 1069 while (cbLeft) 1070 { 1071 if (!pRegs->picb) /* Got a new buffer descriptor, that is, the position is 0? */ 942 1072 { 943 fSignal = true; 944 iIRQL = 1; 1073 Log3Func(("Fresh buffer descriptor %RU8 is empty, addr=%#x, len=%#x, skipping\n", 1074 pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len)); 1075 if (pRegs->civ == pRegs->lvi) 1076 { 1077 pRegs->sr |= AC97_SR_DCH; /** @todo r=andy Also set CELV? */ 1078 pThis->bup_flag = 0; 1079 1080 rc = VINF_EOF; 1081 break; 1082 } 1083 1084 pRegs->sr &= ~AC97_SR_CELV; 1085 if (ichac97R3StreamFetchNextBdle(pDevIns, pStream, pStreamCC)) 1086 ichac97StreamUpdateSR(pDevIns, pThis, pStream, pRegs->sr | AC97_SR_BCIS); 1087 continue; 945 1088 } 946 else if ((new_mask & AC97_SR_BCIS) && (pRegs->cr & AC97_CR_IOCE)) 1089 1090 uint32_t cbChunk = cbLeft; 1091 1092 /* 1093 * Output. 1094 */ 1095 if (!fInput) 947 1096 { 948 fSignal = true; 949 iIRQL = 1; 1097 void *pvDst = NULL; 1098 size_t cbDst = 0; 1099 RTCircBufAcquireWriteBlock(pCircBuf, cbChunk, &pvDst, &cbDst); 1100 1101 if (cbDst) 1102 { 1103 int rc2 = PDMDevHlpPCIPhysRead(pDevIns, pRegs->bd.addr, pvDst, cbDst); 1104 AssertRC(rc2); 1105 1106 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled)) 1107 { /* likely */ } 1108 else 1109 AudioHlpFileWrite(pStreamCC->Dbg.Runtime.pFileDMA, pvDst, cbDst, 0 /* fFlags */); 1110 } 1111 1112 RTCircBufReleaseWriteBlock(pCircBuf, cbDst); 1113 1114 cbChunk = (uint32_t)cbDst; /* Update the current chunk size to what really has been written. */ 950 1115 } 951 } 952 953 pRegs->sr = new_sr; 954 955 LogFlowFunc(("IOC%d, LVB%d, sr=%#x, fSignal=%RTbool, IRQL=%d\n", 956 pRegs->sr & AC97_SR_BCIS, pRegs->sr & AC97_SR_LVBCI, pRegs->sr, fSignal, iIRQL)); 957 958 if (fSignal) 959 { 960 static uint32_t const s_aMasks[] = { AC97_GS_PIINT, AC97_GS_POINT, AC97_GS_MINT }; 961 Assert(pStream->u8SD < AC97_MAX_STREAMS); 962 if (iIRQL) 963 pThis->glob_sta |= s_aMasks[pStream->u8SD]; 964 else 965 pThis->glob_sta &= ~s_aMasks[pStream->u8SD]; 966 967 LogFlowFunc(("Setting IRQ level=%d\n", iIRQL)); 968 PDMDevHlpPCISetIrq(pDevIns, 0, iIRQL); 969 } 970 } 971 972 /** 973 * Writes a new value to a stream's status register (SR). 974 * 975 * @param pDevIns The device instance. 976 * @param pThis The shared AC'97 device state. 977 * @param pStream Stream to update SR for. 978 * @param u32Val New value to set the stream's SR to. 979 */ 980 static void ichac97StreamWriteSR(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, uint32_t u32Val) 981 { 982 PAC97BMREGS pRegs = &pStream->Regs; 983 984 Log3Func(("[SD%RU8] SR <- %#x (sr %#x)\n", pStream->u8SD, u32Val, pRegs->sr)); 985 986 pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK); 987 ichac97StreamUpdateSR(pDevIns, pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK)); 988 } 989 990 #ifdef IN_RING3 991 992 /** 993 * Returns whether an AC'97 stream is enabled or not. 994 * 995 * @returns VBox status code. 996 * @param pThisCC The ring-3 AC'97 device state. 997 * @param pStream Stream to return status for. 998 */ 999 static bool ichac97R3StreamIsEnabled(PAC97STATER3 pThisCC, PAC97STREAM pStream) 1000 { 1001 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD); 1002 bool fIsEnabled = pSink && (AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING); 1003 1004 LogFunc(("[SD%RU8] fIsEnabled=%RTbool\n", pStream->u8SD, fIsEnabled)); 1005 return fIsEnabled; 1006 } 1007 1008 /** 1009 * Enables or disables an AC'97 audio stream. 1010 * 1011 * @returns VBox status code. 1012 * @param pDevIns The device instance. 1013 * @param pThis The shared AC'97 state. 1014 * @param pThisCC The ring-3 AC'97 state. 1015 * @param pStream The AC'97 stream to enable or disable (shared state). 1016 * @param pStreamCC The ring-3 stream state (matching to @a pStream). 1017 * @param fEnable Whether to enable or disable the stream. 1018 * 1019 */ 1020 static int ichac97R3StreamEnable(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC, 1021 PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, bool fEnable) 1022 { 1023 ichac97R3StreamLock(pStreamCC); 1024 PAUDMIXSINK const pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD); 1025 AudioMixerSinkLock(pSink); 1026 1027 int rc = VINF_SUCCESS; 1028 if (fEnable) 1029 { 1030 /* Reset some of the state. */ 1031 pStreamCC->State.fInputPreBuffered = false; 1032 if (pStreamCC->State.pCircBuf) 1033 RTCircBufReset(pStreamCC->State.pCircBuf); 1034 1035 /* (Re-)Open the stream if necessary. */ 1036 rc = ichac97R3StreamOpen(pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fForce */); 1037 1038 /* Re-register the update job with the AIO thread with correct sched hint. 1039 Note! We do not unregister it on disable because of draining. */ 1040 if (pStreamCC->State.fRegisteredAsyncUpdateJob) 1041 AudioMixerSinkRemoveUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC); 1042 int rc2 = AudioMixerSinkAddUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC, 1043 pStreamCC->State.Cfg.Device.cMsSchedulingHint); 1044 AssertRC(rc2); 1045 pStreamCC->State.fRegisteredAsyncUpdateJob = RT_SUCCESS(rc2) || rc2 == VERR_ALREADY_EXISTS; 1046 1047 /* Open debug files: */ 1048 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled)) 1049 { /* likely */ } 1116 /* 1117 * Input. 1118 */ 1050 1119 else 1051 1120 { 1052 if (! AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileStream))1121 if (!fWriteSilence) 1053 1122 { 1054 rc2 = AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileStream, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS, 1055 &pStreamCC->State.Cfg.Props); 1056 AssertRC(rc2); 1123 void *pvSrc = NULL; 1124 size_t cbSrc = 0; 1125 RTCircBufAcquireReadBlock(pCircBuf, cbChunk, &pvSrc, &cbSrc); 1126 1127 if (cbSrc) 1128 { 1129 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, pvSrc, cbSrc); 1130 AssertRC(rc2); 1131 1132 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled)) 1133 { /* likely */ } 1134 else 1135 AudioHlpFileWrite(pStreamCC->Dbg.Runtime.pFileDMA, pvSrc, cbSrc, 0 /* fFlags */); 1136 } 1137 1138 RTCircBufReleaseReadBlock(pCircBuf, cbSrc); 1139 1140 cbChunk = (uint32_t)cbSrc; /* Update the current chunk size to what really has been read. */ 1057 1141 } 1058 1059 if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileDMA)) 1142 else 1060 1143 { 1061 rc2 = AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileDMA, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS, 1062 &pStreamCC->State.Cfg.Props); 1144 /* Since the format is signed 16-bit or 32-bit integer samples, we can 1145 use g_abRTZero64K as source and avoid some unnecessary bzero() work. */ 1146 cbChunk = RT_MIN(cbChunk, sizeof(g_abRTZero64K)); 1147 cbChunk = PDMAudioPropsFloorBytesToFrame(&pStreamCC->State.Cfg.Props, cbChunk); 1148 1149 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, g_abRTZero64K, cbChunk); 1063 1150 AssertRC(rc2); 1064 1151 } 1065 1152 } 1066 1153 1067 if (RT_SUCCESS(rc)) 1068 rc = AudioMixerSinkStart(pSink); 1069 } 1070 else 1071 { 1072 rc = ichac97R3StreamClose(pStream); 1073 if (RT_SUCCESS(rc)) 1074 rc = AudioMixerSinkDrainAndStop(pSink, 1075 pStreamCC->State.pCircBuf ? (uint32_t)RTCircBufUsed(pStreamCC->State.pCircBuf) : 0); 1076 } 1077 1078 /* Make sure to leave the lock before (eventually) starting the timer. */ 1079 AudioMixerSinkUnlock(pSink); 1154 if (cbChunk) 1155 { 1156 Assert(PDMAudioPropsIsSizeAligned(&pStreamCC->State.Cfg.Props, cbChunk)); 1157 Assert(cbChunk <= cbLeft); 1158 1159 cbProcessedTotal += cbChunk; 1160 Assert(cbProcessedTotal <= cbToProcessMax); 1161 cbLeft -= cbChunk; 1162 pRegs->picb -= (cbChunk >> 1); /** @todo r=andy Assumes 16bit samples. */ 1163 pRegs->bd.addr += cbChunk; 1164 } 1165 1166 LogFlowFunc(("[SD%RU8] cbChunk=%RU32, cbLeft=%RU32, cbTotal=%RU32, rc=%Rrc\n", 1167 pStream->u8SD, cbChunk, cbLeft, cbProcessedTotal, rc)); 1168 1169 if (!pRegs->picb) 1170 { 1171 uint32_t new_sr = pRegs->sr & ~AC97_SR_CELV; 1172 1173 if (pRegs->bd.ctl_len & AC97_BD_IOC) 1174 { 1175 new_sr |= AC97_SR_BCIS; 1176 } 1177 1178 if (pRegs->civ == pRegs->lvi) 1179 { 1180 /* Did we run out of data? */ 1181 LogFunc(("Underrun CIV (%RU8) == LVI (%RU8)\n", pRegs->civ, pRegs->lvi)); 1182 1183 new_sr |= AC97_SR_LVBCI | AC97_SR_DCH | AC97_SR_CELV; 1184 pThis->bup_flag = (pRegs->bd.ctl_len & AC97_BD_BUP) ? BUP_LAST : 0; 1185 1186 rc = VINF_EOF; 1187 } 1188 else 1189 new_sr |= ichac97R3StreamFetchNextBdle(pDevIns, pStream, pStreamCC); 1190 1191 ichac97StreamUpdateSR(pDevIns, pThis, pStream, new_sr); 1192 } 1193 1194 /* All data processed? */ 1195 if (rc == VINF_EOF) 1196 break; 1197 } 1198 1080 1199 ichac97R3StreamUnlock(pStreamCC); 1081 LogFunc(("[SD%RU8] fEnable=%RTbool, rc=%Rrc\n", pStream->u8SD, fEnable, rc)); 1200 1201 LogFlowFuncLeaveRC(rc); 1082 1202 return rc; 1083 }1084 1085 /**1086 * Resets an AC'97 stream.1087 *1088 * @param pThis The shared AC'97 state.1089 * @param pStream The AC'97 stream to reset (shared).1090 * @param pStreamCC The AC'97 stream to reset (ring-3).1091 */1092 static void ichac97R3StreamReset(PAC97STATE pThis, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)1093 {1094 ichac97R3StreamLock(pStreamCC);1095 1096 LogFunc(("[SD%RU8]\n", pStream->u8SD));1097 1098 if (pStreamCC->State.pCircBuf)1099 RTCircBufReset(pStreamCC->State.pCircBuf);1100 1101 PAC97BMREGS pRegs = &pStream->Regs;1102 1103 pRegs->bdbar = 0;1104 pRegs->civ = 0;1105 pRegs->lvi = 0;1106 1107 pRegs->picb = 0;1108 pRegs->piv = 0; /* Note! Because this is also zero, we will actually start transferring with BDLE00. */1109 pRegs->cr = pRegs->cr & AC97_CR_DONT_CLEAR_MASK;1110 pRegs->bd_valid = 0;1111 1112 RT_ZERO(pThis->silence);1113 1114 ichac97R3StreamUnlock(pStreamCC);1115 }1116 1117 /**1118 * Creates an AC'97 audio stream.1119 *1120 * @returns VBox status code.1121 * @param pThisCC The ring-3 AC'97 state.1122 * @param pStream The AC'97 stream to create (shared).1123 * @param pStreamCC The AC'97 stream to create (ring-3).1124 * @param u8SD Stream descriptor number to assign.1125 */1126 static int ichac97R3StreamCreate(PAC97STATER3 pThisCC, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, uint8_t u8SD)1127 {1128 LogFunc(("[SD%RU8] pStream=%p\n", u8SD, pStream));1129 1130 AssertReturn(u8SD < AC97_MAX_STREAMS, VERR_INVALID_PARAMETER);1131 pStream->u8SD = u8SD;1132 pStreamCC->u8SD = u8SD;1133 1134 int rc = RTCritSectInit(&pStreamCC->State.CritSect);1135 AssertRCReturn(rc, rc);1136 1137 pStreamCC->Dbg.Runtime.fEnabled = pThisCC->Dbg.fEnabled;1138 1139 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))1140 { /* likely */ }1141 else1142 {1143 char szFile[64];1144 1145 if (ichac97GetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)1146 RTStrPrintf(szFile, sizeof(szFile), "ac97StreamWriteSD%RU8", pStream->u8SD);1147 else1148 RTStrPrintf(szFile, sizeof(szFile), "ac97StreamReadSD%RU8", pStream->u8SD);1149 1150 char szPath[RTPATH_MAX];1151 int rc2 = AudioHlpFileNameGet(szPath, sizeof(szPath), pThisCC->Dbg.pszOutPath, szFile,1152 0 /* uInst */, AUDIOHLPFILETYPE_WAV, AUDIOHLPFILENAME_FLAGS_NONE);1153 AssertRC(rc2);1154 rc2 = AudioHlpFileCreate(AUDIOHLPFILETYPE_WAV, szPath, AUDIOHLPFILE_FLAGS_NONE, &pStreamCC->Dbg.Runtime.pFileStream);1155 AssertRC(rc2);1156 1157 if (ichac97GetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)1158 RTStrPrintf(szFile, sizeof(szFile), "ac97DMAWriteSD%RU8", pStream->u8SD);1159 else1160 RTStrPrintf(szFile, sizeof(szFile), "ac97DMAReadSD%RU8", pStream->u8SD);1161 1162 rc2 = AudioHlpFileNameGet(szPath, sizeof(szPath), pThisCC->Dbg.pszOutPath, szFile,1163 0 /* uInst */, AUDIOHLPFILETYPE_WAV, AUDIOHLPFILENAME_FLAGS_NONE);1164 AssertRC(rc2);1165 1166 rc2 = AudioHlpFileCreate(AUDIOHLPFILETYPE_WAV, szPath, AUDIOHLPFILE_FLAGS_NONE, &pStreamCC->Dbg.Runtime.pFileDMA);1167 AssertRC(rc2);1168 1169 /* Delete stale debugging files from a former run. */1170 AudioHlpFileDelete(pStreamCC->Dbg.Runtime.pFileStream);1171 AudioHlpFileDelete(pStreamCC->Dbg.Runtime.pFileDMA);1172 }1173 1174 return rc;1175 }1176 1177 /**1178 * Destroys an AC'97 audio stream.1179 *1180 * @returns VBox status code.1181 * @param pThisCC The ring-3 AC'97 state.1182 * @param pStream The AC'97 stream to destroy (shared).1183 * @param pStreamCC The AC'97 stream to destroy (ring-3).1184 */1185 static void ichac97R3StreamDestroy(PAC97STATER3 pThisCC, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)1186 {1187 LogFlowFunc(("[SD%RU8]\n", pStream->u8SD));1188 1189 ichac97R3StreamClose(pStream);1190 1191 int rc2 = RTCritSectDelete(&pStreamCC->State.CritSect);1192 AssertRC(rc2);1193 1194 if (pStreamCC->State.fRegisteredAsyncUpdateJob)1195 {1196 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD);1197 if (pSink)1198 AudioMixerSinkRemoveUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC);1199 pStreamCC->State.fRegisteredAsyncUpdateJob = false;1200 }1201 1202 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled))1203 { /* likely */ }1204 else1205 {1206 AudioHlpFileDestroy(pStreamCC->Dbg.Runtime.pFileStream);1207 pStreamCC->Dbg.Runtime.pFileStream = NULL;1208 1209 AudioHlpFileDestroy(pStreamCC->Dbg.Runtime.pFileDMA);1210 pStreamCC->Dbg.Runtime.pFileDMA = NULL;1211 }1212 1213 if (pStreamCC->State.pCircBuf)1214 {1215 RTCircBufDestroy(pStreamCC->State.pCircBuf);1216 pStreamCC->State.pCircBuf = NULL;1217 }1218 1219 LogFlowFuncLeave();1220 }1221 1222 /**1223 * Destroys all AC'97 audio streams of the device.1224 *1225 * @param pDevIns The device AC'97 instance.1226 * @param pThis The shared AC'97 state.1227 * @param pThisCC The ring-3 AC'97 state.1228 */1229 static void ichac97R3StreamsDestroy(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC)1230 {1231 LogFlowFuncEnter();1232 1233 /*1234 * Destroy all AC'97 streams.1235 */1236 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++)1237 ichac97R3StreamDestroy(pThisCC, &pThis->aStreams[i], &pThisCC->aStreams[i]);1238 1239 /*1240 * Destroy all sinks.1241 */1242 if (pThisCC->pSinkLineIn)1243 {1244 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pThisCC->pSinkLineIn, PDMAUDIODIR_IN, PDMAUDIOPATH_IN_LINE);1245 1246 AudioMixerSinkDestroy(pThisCC->pSinkLineIn, pDevIns);1247 pThisCC->pSinkLineIn = NULL;1248 }1249 1250 if (pThisCC->pSinkMicIn)1251 {1252 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pThisCC->pSinkMicIn, PDMAUDIODIR_IN, PDMAUDIOPATH_IN_MIC);1253 1254 AudioMixerSinkDestroy(pThisCC->pSinkMicIn, pDevIns);1255 pThisCC->pSinkMicIn = NULL;1256 }1257 1258 if (pThisCC->pSinkOut)1259 {1260 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pThisCC->pSinkOut, PDMAUDIODIR_OUT, PDMAUDIOPATH_OUT_FRONT);1261 1262 AudioMixerSinkDestroy(pThisCC->pSinkOut, pDevIns);1263 pThisCC->pSinkOut = NULL;1264 }1265 1203 } 1266 1204 … … 1275 1213 static void ichac97R3StreamPullFromMixer(PAC97STREAMR3 pStreamR3, PAUDMIXSINK pSink) 1276 1214 { 1277 # ifdef LOG_ENABLED1215 # ifdef LOG_ENABLED 1278 1216 uint64_t const offWriteOld = pStreamR3->State.offWrite; 1279 # endif1217 # endif 1280 1218 pStreamR3->State.offWrite = AudioMixerSinkTransferToCircBuf(pSink, 1281 1219 pStreamR3->State.pCircBuf, … … 1301 1239 static void ichac97R3StreamPushToMixer(PAC97STREAMR3 pStreamR3, PAUDMIXSINK pSink) 1302 1240 { 1303 # ifdef LOG_ENABLED1241 # ifdef LOG_ENABLED 1304 1242 uint64_t const offReadOld = pStreamR3->State.offRead; 1305 # endif1243 # endif 1306 1244 pStreamR3->State.offRead = AudioMixerSinkTransferFromCircBuf(pSink, 1307 1245 pStreamR3->State.pCircBuf, … … 1331 1269 * @param pStream The AC'97 stream to update (shared). 1332 1270 * @param pStreamCC The AC'97 stream to update (ring-3). 1271 * @param pSink The sink being updated. 1333 1272 */ 1334 1273 static void ichac97R3StreamUpdateDma(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC, … … 1566 1505 } 1567 1506 1507 1508 /** 1509 * Updates the next transfer based on a specific amount of bytes. 1510 * 1511 * @param pDevIns The device instance. 1512 * @param pStream The AC'97 stream to update (shared). 1513 * @param pStreamCC The AC'97 stream to update (ring-3). 1514 */ 1515 static void ichac97R3StreamTransferUpdate(PPDMDEVINS pDevIns, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC) 1516 { 1517 /* 1518 * Get the number of bytes left in the current buffer. 1519 * 1520 * This isn't entirely optimal iff the current entry doesn't have IOC set, in 1521 * that case we should use the number of bytes to the next IOC. Unfortuantely, 1522 * it seems the spec doesn't allow us to prefetch more than one BDLE, so we 1523 * probably cannot look ahead without violating that restriction. This is 1524 * probably a purely theoretical problem at this point. 1525 */ 1526 uint32_t const cbLeftInBdle = pStream->Regs.picb * PDMAudioPropsSampleSize(&pStreamCC->State.Cfg.Props); 1527 if (cbLeftInBdle > 0) /** @todo r=bird: see todo about this in ichac97R3StreamFetchBDLE. */ 1528 { 1529 /* 1530 * Since the buffer can be up to 0xfffe samples long (frame aligning stereo 1531 * prevents 0xffff), which translates to 743ms at a 44.1kHz rate, we must 1532 * also take the nominal timer frequency into account here so we keep 1533 * moving data at a steady rate. (In theory, I think the guest can even 1534 * set up just one buffer and anticipate where we are in the buffer 1535 * processing when it writes/reads from it. Linux seems to be doing such 1536 * configs when not playing or something.) 1537 */ 1538 uint32_t const cbMaxPerHz = PDMAudioPropsNanoToBytes(&pStreamCC->State.Cfg.Props, RT_NS_1SEC / pStreamCC->State.uTimerHz); 1539 1540 if (cbLeftInBdle <= cbMaxPerHz) 1541 pStreamCC->State.cbTransferChunk = cbLeftInBdle; 1542 /* Try avoid leaving a very short period at the end of a buffer. */ 1543 else if (cbLeftInBdle >= cbMaxPerHz + cbMaxPerHz / 2) 1544 pStreamCC->State.cbTransferChunk = cbMaxPerHz; 1545 else 1546 pStreamCC->State.cbTransferChunk = PDMAudioPropsFloorBytesToFrame(&pStreamCC->State.Cfg.Props, cbLeftInBdle / 2); 1547 1548 /* 1549 * Translate the chunk size to timer ticks. 1550 */ 1551 uint64_t const cNsXferChunk = PDMAudioPropsBytesToNano(&pStreamCC->State.Cfg.Props, pStreamCC->State.cbTransferChunk); 1552 pStreamCC->State.cTransferTicks = PDMDevHlpTimerFromNano(pDevIns, pStream->hTimer, cNsXferChunk); 1553 Assert(pStreamCC->State.cTransferTicks > 0); 1554 1555 Log3Func(("[SD%RU8] cbLeftInBdle=%#RX32 cbMaxPerHz=%#RX32 (%RU16Hz) -> cbTransferChunk=%#RX32 cTransferTicks=%RX64\n", 1556 pStream->u8SD, cbLeftInBdle, cbMaxPerHz, pStreamCC->State.uTimerHz, 1557 pStreamCC->State.cbTransferChunk, pStreamCC->State.cTransferTicks)); 1558 } 1559 } 1560 1561 1562 /** 1563 * Sets the virtual device timer to a new expiration time. 1564 * 1565 * @param pDevIns The device instance. 1566 * @param pStream AC'97 stream to set timer for. 1567 * @param cTicksToDeadline The number of ticks to the new deadline. 1568 * 1569 * @remarks This used to be more complicated a long time ago... 1570 */ 1571 DECLINLINE(void) ichac97R3TimerSet(PPDMDEVINS pDevIns, PAC97STREAM pStream, uint64_t cTicksToDeadline) 1572 { 1573 int rc = PDMDevHlpTimerSetRelative(pDevIns, pStream->hTimer, cTicksToDeadline, NULL /*pu64Now*/); 1574 AssertRC(rc); 1575 } 1576 1577 1578 /** 1579 * @callback_method_impl{FNTMTIMERDEV, 1580 * Timer callback which handles the audio data transfers on a periodic basis.} 1581 */ 1582 static DECLCALLBACK(void) ichac97R3Timer(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser) 1583 { 1584 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE); 1585 STAM_PROFILE_START(&pThis->StatTimer, a); 1586 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3); 1587 PAC97STREAM pStream = (PAC97STREAM)pvUser; 1588 PAC97STREAMR3 pStreamCC = &RT_SAFE_SUBSCRIPT8(pThisCC->aStreams, pStream->u8SD); 1589 Assert(hTimer == pStream->hTimer); RT_NOREF(hTimer); 1590 1591 Assert(pStream - &pThis->aStreams[0] == pStream->u8SD); 1592 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect)); 1593 Assert(PDMDevHlpTimerIsLockOwner(pDevIns, pStream->hTimer)); 1594 1595 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD); 1596 if (pSink && AudioMixerSinkIsActive(pSink)) 1597 { 1598 ichac97R3StreamUpdateDma(pDevIns, pThis, pThisCC, pStream, pStreamCC, pSink); 1599 1600 ichac97R3StreamTransferUpdate(pDevIns, pStream, pStreamCC); 1601 ichac97R3TimerSet(pDevIns, pStream, pStreamCC->State.cTransferTicks); 1602 } 1603 1604 STAM_PROFILE_STOP(&pThis->StatTimer, a); 1605 } 1606 1568 1607 #endif /* IN_RING3 */ 1569 1608 1570 /** 1571 * Sets a AC'97 mixer control to a specific value. 1609 1610 /********************************************************************************************************************************* 1611 * AC'97 Stream Management * 1612 *********************************************************************************************************************************/ 1613 #ifdef IN_RING3 1614 1615 /** 1616 * Locks an AC'97 stream for serialized access. 1572 1617 * 1573 1618 * @returns VBox status code. 1619 * @param pStreamCC The AC'97 stream to lock (ring-3). 1620 */ 1621 static void ichac97R3StreamLock(PAC97STREAMR3 pStreamCC) 1622 { 1623 int rc2 = RTCritSectEnter(&pStreamCC->State.CritSect); 1624 AssertRC(rc2); 1625 } 1626 1627 /** 1628 * Unlocks a formerly locked AC'97 stream. 1629 * 1630 * @returns VBox status code. 1631 * @param pStreamCC The AC'97 stream to unlock (ring-3). 1632 */ 1633 static void ichac97R3StreamUnlock(PAC97STREAMR3 pStreamCC) 1634 { 1635 int rc2 = RTCritSectLeave(&pStreamCC->State.CritSect); 1636 AssertRC(rc2); 1637 } 1638 1639 #endif /* IN_RING3 */ 1640 1641 /** 1642 * Updates the status register (SR) of an AC'97 audio stream. 1643 * 1644 * @param pDevIns The device instance. 1574 1645 * @param pThis The shared AC'97 state. 1575 * @param uMixerIdx Mixer control to set value for. 1576 * @param uVal Value to set. 1577 */ 1578 static void ichac97MixerSet(PAC97STATE pThis, uint8_t uMixerIdx, uint16_t uVal) 1579 { 1580 AssertMsgReturnVoid(uMixerIdx + 2U <= sizeof(pThis->mixer_data), 1581 ("Index %RU8 out of bounds (%zu)\n", uMixerIdx, sizeof(pThis->mixer_data))); 1582 1583 LogRel2(("AC97: Setting mixer index #%RU8 to %RU16 (%RU8 %RU8)\n", 1584 uMixerIdx, uVal, RT_HI_U8(uVal), RT_LO_U8(uVal))); 1585 1586 pThis->mixer_data[uMixerIdx + 0] = RT_LO_U8(uVal); 1587 pThis->mixer_data[uMixerIdx + 1] = RT_HI_U8(uVal); 1588 } 1589 1590 /** 1591 * Gets a value from a specific AC'97 mixer control. 1592 * 1593 * @returns Retrieved mixer control value. 1646 * @param pStream AC'97 stream to update SR for. 1647 * @param new_sr New value for status register (SR). 1648 */ 1649 static void ichac97StreamUpdateSR(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, uint32_t new_sr) 1650 { 1651 PAC97BMREGS pRegs = &pStream->Regs; 1652 1653 bool fSignal = false; 1654 int iIRQL = 0; 1655 1656 uint32_t new_mask = new_sr & AC97_SR_INT_MASK; 1657 uint32_t old_mask = pRegs->sr & AC97_SR_INT_MASK; 1658 1659 if (new_mask ^ old_mask) 1660 { 1661 /** @todo Is IRQ deasserted when only one of status bits is cleared? */ 1662 if (!new_mask) 1663 { 1664 fSignal = true; 1665 iIRQL = 0; 1666 } 1667 else if ((new_mask & AC97_SR_LVBCI) && (pRegs->cr & AC97_CR_LVBIE)) 1668 { 1669 fSignal = true; 1670 iIRQL = 1; 1671 } 1672 else if ((new_mask & AC97_SR_BCIS) && (pRegs->cr & AC97_CR_IOCE)) 1673 { 1674 fSignal = true; 1675 iIRQL = 1; 1676 } 1677 } 1678 1679 pRegs->sr = new_sr; 1680 1681 LogFlowFunc(("IOC%d, LVB%d, sr=%#x, fSignal=%RTbool, IRQL=%d\n", 1682 pRegs->sr & AC97_SR_BCIS, pRegs->sr & AC97_SR_LVBCI, pRegs->sr, fSignal, iIRQL)); 1683 1684 if (fSignal) 1685 { 1686 static uint32_t const s_aMasks[] = { AC97_GS_PIINT, AC97_GS_POINT, AC97_GS_MINT }; 1687 Assert(pStream->u8SD < AC97_MAX_STREAMS); 1688 if (iIRQL) 1689 pThis->glob_sta |= s_aMasks[pStream->u8SD]; 1690 else 1691 pThis->glob_sta &= ~s_aMasks[pStream->u8SD]; 1692 1693 LogFlowFunc(("Setting IRQ level=%d\n", iIRQL)); 1694 PDMDevHlpPCISetIrq(pDevIns, 0, iIRQL); 1695 } 1696 } 1697 1698 /** 1699 * Writes a new value to a stream's status register (SR). 1700 * 1701 * @param pDevIns The device instance. 1702 * @param pThis The shared AC'97 device state. 1703 * @param pStream Stream to update SR for. 1704 * @param u32Val New value to set the stream's SR to. 1705 */ 1706 static void ichac97StreamWriteSR(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, uint32_t u32Val) 1707 { 1708 PAC97BMREGS pRegs = &pStream->Regs; 1709 1710 Log3Func(("[SD%RU8] SR <- %#x (sr %#x)\n", pStream->u8SD, u32Val, pRegs->sr)); 1711 1712 pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK); 1713 ichac97StreamUpdateSR(pDevIns, pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK)); 1714 } 1715 1716 #ifdef IN_RING3 1717 1718 /** 1719 * Resets an AC'97 stream. 1720 * 1594 1721 * @param pThis The shared AC'97 state. 1595 * @param uMixerIdx Mixer control to get value for. 1596 */ 1597 static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t uMixerIdx) 1598 { 1599 AssertMsgReturn(uMixerIdx + 2U <= sizeof(pThis->mixer_data), 1600 ("Index %RU8 out of bounds (%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)), 1601 UINT16_MAX); 1602 return RT_MAKE_U16(pThis->mixer_data[uMixerIdx + 0], pThis->mixer_data[uMixerIdx + 1]); 1603 } 1604 1605 #ifdef IN_RING3 1722 * @param pStream The AC'97 stream to reset (shared). 1723 * @param pStreamCC The AC'97 stream to reset (ring-3). 1724 */ 1725 static void ichac97R3StreamReset(PAC97STATE pThis, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC) 1726 { 1727 ichac97R3StreamLock(pStreamCC); 1728 1729 LogFunc(("[SD%RU8]\n", pStream->u8SD)); 1730 1731 if (pStreamCC->State.pCircBuf) 1732 RTCircBufReset(pStreamCC->State.pCircBuf); 1733 1734 PAC97BMREGS pRegs = &pStream->Regs; 1735 1736 pRegs->bdbar = 0; 1737 pRegs->civ = 0; 1738 pRegs->lvi = 0; 1739 1740 pRegs->picb = 0; 1741 pRegs->piv = 0; /* Note! Because this is also zero, we will actually start transferring with BDLE00. */ 1742 pRegs->cr = pRegs->cr & AC97_CR_DONT_CLEAR_MASK; 1743 pRegs->bd_valid = 0; 1744 1745 RT_ZERO(pThis->silence); 1746 1747 ichac97R3StreamUnlock(pStreamCC); 1748 } 1606 1749 1607 1750 /** … … 1667 1810 AssertPtrReturn(pMixSink, VERR_INVALID_POINTER); 1668 1811 1669 PPDMAUDIOSTREAMCFG pStreamCfg = PDMAudioStrmCfgDup(pCfg); 1812 PPDMAUDIOSTREAMCFG pStreamCfg = PDMAudioStrmCfgDup(pCfg); /** @todo r=bird: This seems kind of pointless... */ 1670 1813 if (!pStreamCfg) 1671 1814 return VERR_NO_MEMORY; … … 1853 1996 { 1854 1997 ichac97R3MixerRemoveDrvStream(pDevIns, pMixSink, enmDir, enmPath, pDrv); 1855 }1856 }1857 1858 1859 /**1860 * Updates the next transfer based on a specific amount of bytes.1861 *1862 * @param pDevIns The device instance.1863 * @param pStream The AC'97 stream to update (shared).1864 * @param pStreamCC The AC'97 stream to update (ring-3).1865 */1866 static void ichac97R3StreamTransferUpdate(PPDMDEVINS pDevIns, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC)1867 {1868 /*1869 * Get the number of bytes left in the current buffer.1870 *1871 * This isn't entirely optimal iff the current entry doesn't have IOC set, in1872 * that case we should use the number of bytes to the next IOC. Unfortuantely,1873 * it seems the spec doesn't allow us to prefetch more than one BDLE, so we1874 * probably cannot look ahead without violating that restriction. This is1875 * probably a purely theoretical problem at this point.1876 */1877 uint32_t const cbLeftInBdle = pStream->Regs.picb * PDMAudioPropsSampleSize(&pStreamCC->State.Cfg.Props);1878 if (cbLeftInBdle > 0) /** @todo r=bird: see todo about this in ichac97R3StreamFetchBDLE. */1879 {1880 /*1881 * Since the buffer can be up to 0xfffe samples long (frame aligning stereo1882 * prevents 0xffff), which translates to 743ms at a 44.1kHz rate, we must1883 * also take the nominal timer frequency into account here so we keep1884 * moving data at a steady rate. (In theory, I think the guest can even1885 * set up just one buffer and anticipate where we are in the buffer1886 * processing when it writes/reads from it. Linux seems to be doing such1887 * configs when not playing or something.)1888 */1889 uint32_t const cbMaxPerHz = PDMAudioPropsNanoToBytes(&pStreamCC->State.Cfg.Props, RT_NS_1SEC / pStreamCC->State.uTimerHz);1890 1891 if (cbLeftInBdle <= cbMaxPerHz)1892 pStreamCC->State.cbTransferChunk = cbLeftInBdle;1893 /* Try avoid leaving a very short period at the end of a buffer. */1894 else if (cbLeftInBdle >= cbMaxPerHz + cbMaxPerHz / 2)1895 pStreamCC->State.cbTransferChunk = cbMaxPerHz;1896 else1897 pStreamCC->State.cbTransferChunk = PDMAudioPropsFloorBytesToFrame(&pStreamCC->State.Cfg.Props, cbLeftInBdle / 2);1898 1899 /*1900 * Translate the chunk size to timer ticks.1901 */1902 uint64_t const cNsXferChunk = PDMAudioPropsBytesToNano(&pStreamCC->State.Cfg.Props, pStreamCC->State.cbTransferChunk);1903 pStreamCC->State.cTransferTicks = PDMDevHlpTimerFromNano(pDevIns, pStream->hTimer, cNsXferChunk);1904 Assert(pStreamCC->State.cTransferTicks > 0);1905 1906 Log3Func(("[SD%RU8] cbLeftInBdle=%#RX32 cbMaxPerHz=%#RX32 (%RU16Hz) -> cbTransferChunk=%#RX32 cTransferTicks=%RX64\n",1907 pStream->u8SD, cbLeftInBdle, cbMaxPerHz, pStreamCC->State.uTimerHz,1908 pStreamCC->State.cbTransferChunk, pStreamCC->State.cTransferTicks));1909 1998 } 1910 1999 } … … 2229 2318 } 2230 2319 2231 /** 2232 * Locks an AC'97 stream for serialized access. 2320 2321 /** 2322 * Enables or disables an AC'97 audio stream. 2233 2323 * 2234 2324 * @returns VBox status code. 2235 * @param pStreamCC The AC'97 stream to lock (ring-3). 2236 */ 2237 static void ichac97R3StreamLock(PAC97STREAMR3 pStreamCC) 2238 { 2239 int rc2 = RTCritSectEnter(&pStreamCC->State.CritSect); 2240 AssertRC(rc2); 2241 } 2242 2243 /** 2244 * Unlocks a formerly locked AC'97 stream. 2245 * 2246 * @returns VBox status code. 2247 * @param pStreamCC The AC'97 stream to unlock (ring-3). 2248 */ 2249 static void ichac97R3StreamUnlock(PAC97STREAMR3 pStreamCC) 2250 { 2251 int rc2 = RTCritSectLeave(&pStreamCC->State.CritSect); 2252 AssertRC(rc2); 2253 } 2254 2255 /** 2256 * Retrieves the available size of (buffered) audio data (in bytes) of a given AC'97 stream. 2257 * 2258 * @returns Available data (in bytes). 2259 * @param pStreamCC The AC'97 stream to retrieve size for (ring-3). 2260 */ 2261 static uint32_t ichac97R3StreamGetUsed(PAC97STREAMR3 pStreamCC) 2262 { 2263 if (!pStreamCC->State.pCircBuf) 2264 return 0; 2265 2266 return (uint32_t)RTCircBufUsed(pStreamCC->State.pCircBuf); 2267 } 2268 2269 /** 2270 * Retrieves the free size of audio data (in bytes) of a given AC'97 stream. 2271 * 2272 * @returns Free data (in bytes). 2273 * @param pStreamCC AC'97 stream to retrieve size for (ring-3). 2274 */ 2275 static uint32_t ichac97R3StreamGetFree(PAC97STREAMR3 pStreamCC) 2276 { 2277 if (!pStreamCC->State.pCircBuf) 2278 return 0; 2279 2280 return (uint32_t)RTCircBufFree(pStreamCC->State.pCircBuf); 2281 } 2282 2283 /** 2284 * Sets the volume of a specific AC'97 mixer control. 2285 * 2286 * This currently only supports attenuation -- gain support is currently not implemented. 2287 * 2288 * @returns VBox status code. 2289 * @param pThis The shared AC'97 state. 2290 * @param pThisCC The ring-3 AC'97 state. 2291 * @param index AC'97 mixer index to set volume for. 2292 * @param enmMixerCtl Corresponding audio mixer sink. 2293 * @param uVal Volume value to set. 2294 */ 2295 static int ichac97R3MixerSetVolume(PAC97STATE pThis, PAC97STATER3 pThisCC, int index, PDMAUDIOMIXERCTL enmMixerCtl, uint32_t uVal) 2296 { 2297 /* 2298 * From AC'97 SoundMax Codec AD1981A/AD1981B: 2299 * "Because AC '97 defines 6-bit volume registers, to maintain compatibility whenever the 2300 * D5 or D13 bits are set to 1, their respective lower five volume bits are automatically 2301 * set to 1 by the Codec logic. On readback, all lower 5 bits will read ones whenever 2302 * these bits are set to 1." 2303 * 2304 * Linux ALSA depends on this behavior to detect that only 5 bits are used for volume 2305 * control and the optional 6th bit is not used. Note that this logic only applies to the 2306 * master volume controls. 2307 */ 2308 if (index == AC97_Master_Volume_Mute || index == AC97_Headphone_Volume_Mute || index == AC97_Master_Volume_Mono_Mute) 2309 { 2310 if (uVal & RT_BIT(5)) /* D5 bit set? */ 2311 uVal |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0); 2312 if (uVal & RT_BIT(13)) /* D13 bit set? */ 2313 uVal |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8); 2314 } 2315 2316 const bool fCtlMuted = (uVal >> AC97_BARS_VOL_MUTE_SHIFT) & 1; 2317 uint8_t uCtlAttLeft = (uVal >> 8) & AC97_BARS_VOL_MASK; 2318 uint8_t uCtlAttRight = uVal & AC97_BARS_VOL_MASK; 2319 2320 /* For the master and headphone volume, 0 corresponds to 0dB attenuation. For the other 2321 * volume controls, 0 means 12dB gain and 8 means unity gain. 2322 */ 2323 if (index != AC97_Master_Volume_Mute && index != AC97_Headphone_Volume_Mute) 2324 { 2325 # ifndef VBOX_WITH_AC97_GAIN_SUPPORT 2326 /* NB: Currently there is no gain support, only attenuation. */ 2327 uCtlAttLeft = uCtlAttLeft < 8 ? 0 : uCtlAttLeft - 8; 2328 uCtlAttRight = uCtlAttRight < 8 ? 0 : uCtlAttRight - 8; 2329 # endif 2330 } 2331 Assert(uCtlAttLeft <= 255 / AC97_DB_FACTOR); 2332 Assert(uCtlAttRight <= 255 / AC97_DB_FACTOR); 2333 2334 LogFunc(("index=0x%x, uVal=%RU32, enmMixerCtl=%RU32\n", index, uVal, enmMixerCtl)); 2335 LogFunc(("uCtlAttLeft=%RU8, uCtlAttRight=%RU8 ", uCtlAttLeft, uCtlAttRight)); 2336 2337 /* 2338 * For AC'97 volume controls, each additional step means -1.5dB attenuation with 2339 * zero being maximum. In contrast, we're internally using 255 (PDMAUDIO_VOLUME_MAX) 2340 * steps, each -0.375dB, where 0 corresponds to -96dB and 255 corresponds to 0dB. 2341 */ 2342 uint8_t lVol = PDMAUDIO_VOLUME_MAX - uCtlAttLeft * AC97_DB_FACTOR; 2343 uint8_t rVol = PDMAUDIO_VOLUME_MAX - uCtlAttRight * AC97_DB_FACTOR; 2344 2345 Log(("-> fMuted=%RTbool, lVol=%RU8, rVol=%RU8\n", fCtlMuted, lVol, rVol)); 2325 * @param pDevIns The device instance. 2326 * @param pThis The shared AC'97 state. 2327 * @param pThisCC The ring-3 AC'97 state. 2328 * @param pStream The AC'97 stream to enable or disable (shared state). 2329 * @param pStreamCC The ring-3 stream state (matching to @a pStream). 2330 * @param fEnable Whether to enable or disable the stream. 2331 * 2332 */ 2333 static int ichac97R3StreamEnable(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC, 2334 PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, bool fEnable) 2335 { 2336 ichac97R3StreamLock(pStreamCC); 2337 PAUDMIXSINK const pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD); 2338 AudioMixerSinkLock(pSink); 2346 2339 2347 2340 int rc = VINF_SUCCESS; 2348 2349 if (pThisCC->pMixer) /* Device can be in reset state, so no mixer available. */ 2350 { 2351 PDMAUDIOVOLUME Vol = { fCtlMuted, lVol, rVol }; 2352 PAUDMIXSINK pSink = NULL; 2353 2354 switch (enmMixerCtl) 2355 { 2356 case PDMAUDIOMIXERCTL_VOLUME_MASTER: 2357 rc = AudioMixerSetMasterVolume(pThisCC->pMixer, &Vol); 2358 break; 2359 2360 case PDMAUDIOMIXERCTL_FRONT: 2361 pSink = pThisCC->pSinkOut; 2362 break; 2363 2364 case PDMAUDIOMIXERCTL_MIC_IN: 2365 case PDMAUDIOMIXERCTL_LINE_IN: 2366 /* These are recognized but do nothing. */ 2367 break; 2368 2369 default: 2370 AssertFailed(); 2371 rc = VERR_NOT_SUPPORTED; 2372 break; 2373 } 2374 2375 if (pSink) 2376 rc = AudioMixerSinkSetVolume(pSink, &Vol); 2377 } 2378 2379 ichac97MixerSet(pThis, index, uVal); 2380 2381 if (RT_FAILURE(rc)) 2382 LogFlowFunc(("Failed with %Rrc\n", rc)); 2383 2384 return rc; 2385 } 2386 2387 /** 2388 * Sets the gain of a specific AC'97 recording control. 2389 * 2390 * NB: gain support is currently not implemented in PDM audio. 2391 * 2392 * @returns VBox status code. 2393 * @param pThis The shared AC'97 state. 2394 * @param pThisCC The ring-3 AC'97 state. 2395 * @param index AC'97 mixer index to set volume for. 2396 * @param enmMixerCtl Corresponding audio mixer sink. 2397 * @param uVal Volume value to set. 2398 */ 2399 static int ichac97R3MixerSetGain(PAC97STATE pThis, PAC97STATER3 pThisCC, int index, PDMAUDIOMIXERCTL enmMixerCtl, uint32_t uVal) 2400 { 2401 /* 2402 * For AC'97 recording controls, each additional step means +1.5dB gain with 2403 * zero being 0dB gain and 15 being +22.5dB gain. 2404 */ 2405 const bool fCtlMuted = (uVal >> AC97_BARS_VOL_MUTE_SHIFT) & 1; 2406 uint8_t uCtlGainLeft = (uVal >> 8) & AC97_BARS_GAIN_MASK; 2407 uint8_t uCtlGainRight = uVal & AC97_BARS_GAIN_MASK; 2408 2409 Assert(uCtlGainLeft <= 255 / AC97_DB_FACTOR); 2410 Assert(uCtlGainRight <= 255 / AC97_DB_FACTOR); 2411 2412 LogFunc(("index=0x%x, uVal=%RU32, enmMixerCtl=%RU32\n", index, uVal, enmMixerCtl)); 2413 LogFunc(("uCtlGainLeft=%RU8, uCtlGainRight=%RU8 ", uCtlGainLeft, uCtlGainRight)); 2414 2415 uint8_t lVol = PDMAUDIO_VOLUME_MAX + uCtlGainLeft * AC97_DB_FACTOR; 2416 uint8_t rVol = PDMAUDIO_VOLUME_MAX + uCtlGainRight * AC97_DB_FACTOR; 2417 2418 /* We do not currently support gain. Since AC'97 does not support attenuation 2419 * for the recording input, the best we can do is set the maximum volume. 2420 */ 2421 # ifndef VBOX_WITH_AC97_GAIN_SUPPORT 2422 /* NB: Currently there is no gain support, only attenuation. Since AC'97 does not 2423 * support attenuation for the recording inputs, the best we can do is set the 2424 * maximum volume. 2425 */ 2426 lVol = rVol = PDMAUDIO_VOLUME_MAX; 2427 # endif 2428 2429 Log(("-> fMuted=%RTbool, lVol=%RU8, rVol=%RU8\n", fCtlMuted, lVol, rVol)); 2430 2431 int rc = VINF_SUCCESS; 2432 2433 if (pThisCC->pMixer) /* Device can be in reset state, so no mixer available. */ 2434 { 2435 PDMAUDIOVOLUME Vol = { fCtlMuted, lVol, rVol }; 2436 PAUDMIXSINK pSink = NULL; 2437 2438 switch (enmMixerCtl) 2439 { 2440 case PDMAUDIOMIXERCTL_MIC_IN: 2441 pSink = pThisCC->pSinkMicIn; 2442 break; 2443 2444 case PDMAUDIOMIXERCTL_LINE_IN: 2445 pSink = pThisCC->pSinkLineIn; 2446 break; 2447 2448 default: 2449 AssertFailed(); 2450 rc = VERR_NOT_SUPPORTED; 2451 break; 2452 } 2453 2454 if (pSink) { 2455 rc = AudioMixerSinkSetVolume(pSink, &Vol); 2456 /* There is only one AC'97 recording gain control. If line in 2457 * is changed, also update the microphone. If the optional dedicated 2458 * microphone is changed, only change that. 2459 * NB: The codecs we support do not have the dedicated microphone control. 2460 */ 2461 if ((pSink == pThisCC->pSinkLineIn) && pThisCC->pSinkMicIn) 2462 rc = AudioMixerSinkSetVolume(pSink, &Vol); 2463 } 2464 } 2465 2466 ichac97MixerSet(pThis, index, uVal); 2467 2468 if (RT_FAILURE(rc)) 2469 LogFlowFunc(("Failed with %Rrc\n", rc)); 2470 2471 return rc; 2472 } 2473 2474 /** 2475 * Converts an AC'97 recording source index to a PDM audio recording source. 2476 * 2477 * @returns PDM audio recording source. 2478 * @param uIdx AC'97 index to convert. 2479 */ 2480 static PDMAUDIOPATH ichac97R3IdxToRecSource(uint8_t uIdx) 2481 { 2482 switch (uIdx) 2483 { 2484 case AC97_REC_MIC: return PDMAUDIOPATH_IN_MIC; 2485 case AC97_REC_CD: return PDMAUDIOPATH_IN_CD; 2486 case AC97_REC_VIDEO: return PDMAUDIOPATH_IN_VIDEO; 2487 case AC97_REC_AUX: return PDMAUDIOPATH_IN_AUX; 2488 case AC97_REC_LINE_IN: return PDMAUDIOPATH_IN_LINE; 2489 case AC97_REC_PHONE: return PDMAUDIOPATH_IN_PHONE; 2490 default: 2491 break; 2492 } 2493 2494 LogFlowFunc(("Unknown record source %d, using MIC\n", uIdx)); 2495 return PDMAUDIOPATH_IN_MIC; 2496 } 2497 2498 /** 2499 * Converts a PDM audio recording source to an AC'97 recording source index. 2500 * 2501 * @returns AC'97 recording source index. 2502 * @param enmRecSrc PDM audio recording source to convert. 2503 */ 2504 static uint8_t ichac97R3RecSourceToIdx(PDMAUDIOPATH enmRecSrc) 2505 { 2506 switch (enmRecSrc) 2507 { 2508 case PDMAUDIOPATH_IN_MIC: return AC97_REC_MIC; 2509 case PDMAUDIOPATH_IN_CD: return AC97_REC_CD; 2510 case PDMAUDIOPATH_IN_VIDEO: return AC97_REC_VIDEO; 2511 case PDMAUDIOPATH_IN_AUX: return AC97_REC_AUX; 2512 case PDMAUDIOPATH_IN_LINE: return AC97_REC_LINE_IN; 2513 case PDMAUDIOPATH_IN_PHONE: return AC97_REC_PHONE; 2514 default: 2515 AssertMsgFailedBreak(("%d\n", enmRecSrc)); 2516 } 2517 2518 LogFlowFunc(("Unknown audio recording source %d using MIC\n", enmRecSrc)); 2519 return AC97_REC_MIC; 2520 } 2521 2522 /** 2523 * Returns the audio direction of a specified stream descriptor. 2524 * 2525 * @return Audio direction. 2526 */ 2527 DECLINLINE(PDMAUDIODIR) ichac97GetDirFromSD(uint8_t uSD) 2528 { 2529 switch (uSD) 2530 { 2531 case AC97SOUNDSOURCE_PI_INDEX: return PDMAUDIODIR_IN; 2532 case AC97SOUNDSOURCE_PO_INDEX: return PDMAUDIODIR_OUT; 2533 case AC97SOUNDSOURCE_MC_INDEX: return PDMAUDIODIR_IN; 2534 } 2535 2536 AssertFailed(); 2537 return PDMAUDIODIR_UNKNOWN; 2538 } 2539 2540 #endif /* IN_RING3 */ 2541 2542 #ifdef IN_RING3 2543 2544 /** 2545 * Performs an AC'97 mixer record select to switch to a different recording 2546 * source. 2547 * 2548 * @param pThis The shared AC'97 state. 2549 * @param val AC'97 recording source index to set. 2550 */ 2551 static void ichac97R3MixerRecordSelect(PAC97STATE pThis, uint32_t val) 2552 { 2553 uint8_t rs = val & AC97_REC_MASK; 2554 uint8_t ls = (val >> 8) & AC97_REC_MASK; 2555 2556 PDMAUDIOPATH const ars = ichac97R3IdxToRecSource(rs); 2557 PDMAUDIOPATH const als = ichac97R3IdxToRecSource(ls); 2558 2559 rs = ichac97R3RecSourceToIdx(ars); 2560 ls = ichac97R3RecSourceToIdx(als); 2561 2562 LogRel(("AC97: Record select to left=%s, right=%s\n", PDMAudioPathGetName(ars), PDMAudioPathGetName(als))); 2563 2564 ichac97MixerSet(pThis, AC97_Record_Select, rs | (ls << 8)); 2565 } 2566 2567 /** 2568 * Resets the AC'97 mixer. 2569 * 2570 * @returns VBox status code. 2571 * @param pThis The shared AC'97 state. 2572 * @param pThisCC The ring-3 AC'97 state. 2573 */ 2574 static int ichac97R3MixerReset(PAC97STATE pThis, PAC97STATER3 pThisCC) 2575 { 2576 LogFlowFuncEnter(); 2577 2578 RT_ZERO(pThis->mixer_data); 2579 2580 /* Note: Make sure to reset all registers first before bailing out on error. */ 2581 2582 ichac97MixerSet(pThis, AC97_Reset , 0x0000); /* 6940 */ 2583 ichac97MixerSet(pThis, AC97_Master_Volume_Mono_Mute , 0x8000); 2584 ichac97MixerSet(pThis, AC97_PC_BEEP_Volume_Mute , 0x0000); 2585 2586 ichac97MixerSet(pThis, AC97_Phone_Volume_Mute , 0x8008); 2587 ichac97MixerSet(pThis, AC97_Mic_Volume_Mute , 0x8008); 2588 ichac97MixerSet(pThis, AC97_CD_Volume_Mute , 0x8808); 2589 ichac97MixerSet(pThis, AC97_Aux_Volume_Mute , 0x8808); 2590 ichac97MixerSet(pThis, AC97_Record_Gain_Mic_Mute , 0x8000); 2591 ichac97MixerSet(pThis, AC97_General_Purpose , 0x0000); 2592 ichac97MixerSet(pThis, AC97_3D_Control , 0x0000); 2593 ichac97MixerSet(pThis, AC97_Powerdown_Ctrl_Stat , 0x000f); 2594 2595 /* Configure Extended Audio ID (EAID) + Control & Status (EACS) registers. */ 2596 const uint16_t fEAID = AC97_EAID_REV1 | AC97_EACS_VRA | AC97_EACS_VRM; /* Our hardware is AC'97 rev2.3 compliant. */ 2597 const uint16_t fEACS = AC97_EACS_VRA | AC97_EACS_VRM; /* Variable Rate PCM Audio (VRA) + Mic-In (VRM) capable. */ 2598 2599 LogRel(("AC97: Mixer reset (EAID=0x%x, EACS=0x%x)\n", fEAID, fEACS)); 2600 2601 ichac97MixerSet(pThis, AC97_Extended_Audio_ID, fEAID); 2602 ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, fEACS); 2603 ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate , 0xbb80 /* 48000 Hz by default */); 2604 ichac97MixerSet(pThis, AC97_PCM_Surround_DAC_Rate , 0xbb80 /* 48000 Hz by default */); 2605 ichac97MixerSet(pThis, AC97_PCM_LFE_DAC_Rate , 0xbb80 /* 48000 Hz by default */); 2606 ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate , 0xbb80 /* 48000 Hz by default */); 2607 ichac97MixerSet(pThis, AC97_MIC_ADC_Rate , 0xbb80 /* 48000 Hz by default */); 2608 2609 if (pThis->enmCodecModel == AC97CODEC_AD1980) 2610 { 2611 /* Analog Devices 1980 (AD1980) */ 2612 ichac97MixerSet(pThis, AC97_Reset , 0x0010); /* Headphones. */ 2613 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144); 2614 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5370); 2615 ichac97MixerSet(pThis, AC97_Headphone_Volume_Mute , 0x8000); 2616 } 2617 else if (pThis->enmCodecModel == AC97CODEC_AD1981B) 2618 { 2619 /* Analog Devices 1981B (AD1981B) */ 2620 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144); 2621 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5374); 2622 } 2623 else 2624 { 2625 /* Sigmatel 9700 (STAC9700) */ 2626 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x8384); 2627 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x7600); /* 7608 */ 2628 } 2629 ichac97R3MixerRecordSelect(pThis, 0); 2630 2631 /* The default value is 8000h, which corresponds to 0 dB attenuation with mute on. */ 2632 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER, 0x8000); 2633 2634 /* The default value for stereo registers is 8808h, which corresponds to 0 dB gain with mute on.*/ 2635 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT, 0x8808); 2636 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808); 2637 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Mic_Volume_Mute, PDMAUDIOMIXERCTL_MIC_IN, 0x8008); 2638 2639 /* The default for record controls is 0 dB gain with mute on. */ 2640 ichac97R3MixerSetGain(pThis, pThisCC, AC97_Record_Gain_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8000); 2641 ichac97R3MixerSetGain(pThis, pThisCC, AC97_Record_Gain_Mic_Mute, PDMAUDIOMIXERCTL_MIC_IN, 0x8000); 2642 2643 return VINF_SUCCESS; 2644 } 2645 2646 # if 0 /* Unused */ 2647 static void ichac97R3WriteBUP(PAC97STATE pThis, uint32_t cbElapsed) 2648 { 2649 LogFlowFunc(("cbElapsed=%RU32\n", cbElapsed)); 2650 2651 if (!(pThis->bup_flag & BUP_SET)) 2652 { 2653 if (pThis->bup_flag & BUP_LAST) 2654 { 2655 unsigned int i; 2656 uint32_t *p = (uint32_t*)pThis->silence; 2657 for (i = 0; i < sizeof(pThis->silence) / 4; i++) /** @todo r=andy Assumes 16-bit samples, stereo. */ 2658 *p++ = pThis->last_samp; 2659 } 2660 else 2661 RT_ZERO(pThis->silence); 2662 2663 pThis->bup_flag |= BUP_SET; 2664 } 2665 2666 while (cbElapsed) 2667 { 2668 uint32_t cbToWrite = RT_MIN(cbElapsed, (uint32_t)sizeof(pThis->silence)); 2669 uint32_t cbWrittenToStream; 2670 2671 int rc2 = AudioMixerSinkWrite(pThisCC->pSinkOut, AUDMIXOP_COPY, 2672 pThis->silence, cbToWrite, &cbWrittenToStream); 2673 if (RT_SUCCESS(rc2)) 2674 { 2675 if (cbWrittenToStream < cbToWrite) /* Lagging behind? */ 2676 LogFlowFunc(("Warning: Only written %RU32 / %RU32 bytes, expect lags\n", cbWrittenToStream, cbToWrite)); 2677 } 2678 2679 /* Always report all data as being written; 2680 * backends who were not able to catch up have to deal with it themselves. */ 2681 Assert(cbElapsed >= cbToWrite); 2682 cbElapsed -= cbToWrite; 2683 } 2684 } 2685 # endif /* Unused */ 2686 2687 /** 2688 * @callback_method_impl{FNTMTIMERDEV, 2689 * Timer callback which handles the audio data transfers on a periodic basis.} 2690 */ 2691 static DECLCALLBACK(void) ichac97R3Timer(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser) 2692 { 2693 PAC97STATE pThis = PDMDEVINS_2_DATA(pDevIns, PAC97STATE); 2694 STAM_PROFILE_START(&pThis->StatTimer, a); 2695 PAC97STATER3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PAC97STATER3); 2696 PAC97STREAM pStream = (PAC97STREAM)pvUser; 2697 PAC97STREAMR3 pStreamCC = &RT_SAFE_SUBSCRIPT8(pThisCC->aStreams, pStream->u8SD); 2698 Assert(hTimer == pStream->hTimer); RT_NOREF(hTimer); 2699 2700 Assert(pStream - &pThis->aStreams[0] == pStream->u8SD); 2701 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect)); 2702 Assert(PDMDevHlpTimerIsLockOwner(pDevIns, pStream->hTimer)); 2703 2704 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD); 2705 if (pSink && AudioMixerSinkIsActive(pSink)) 2706 { 2707 ichac97R3StreamUpdateDma(pDevIns, pThis, pThisCC, pStream, pStreamCC, pSink); 2708 2709 ichac97R3StreamTransferUpdate(pDevIns, pStream, pStreamCC); 2710 ichac97R3TimerSet(pDevIns, pStream, pStreamCC->State.cTransferTicks); 2711 } 2712 2713 STAM_PROFILE_STOP(&pThis->StatTimer, a); 2714 } 2715 2716 2717 /** 2718 * Sets the virtual device timer to a new expiration time. 2719 * 2720 * @param pDevIns The device instance. 2721 * @param pStream AC'97 stream to set timer for. 2722 * @param cTicksToDeadline The number of ticks to the new deadline. 2723 * 2724 * @remarks This used to be more complicated a long time ago... 2725 */ 2726 DECLINLINE(void) ichac97R3TimerSet(PPDMDEVINS pDevIns, PAC97STREAM pStream, uint64_t cTicksToDeadline) 2727 { 2728 int rc = PDMDevHlpTimerSetRelative(pDevIns, pStream->hTimer, cTicksToDeadline, NULL /*pu64Now*/); 2729 AssertRC(rc); 2730 } 2731 2732 2733 /** 2734 * Transfers data of an AC'97 stream according to its usage (input / output). 2735 * 2736 * For an SDO (output) stream this means reading DMA data from the device to 2737 * the AC'97 stream's internal FIFO buffer. 2738 * 2739 * For an SDI (input) stream this is reading audio data from the AC'97 stream's 2740 * internal FIFO buffer and writing it as DMA data to the device. 2741 * 2742 * @returns VBox status code. 2743 * @param pDevIns The device instance. 2744 * @param pThis The shared AC'97 state. 2745 * @param pStream The AC'97 stream to update (shared). 2746 * @param pStreamCC The AC'97 stream to update (ring-3). 2747 * @param cbToProcessMax Maximum of data (in bytes) to process. 2748 * @param fWriteSilence Whether to write silence if this is an input 2749 * stream (done while waiting for backend to get 2750 * going). 2751 * @param fInput Set if input, clear if output. 2752 */ 2753 static int ichac97R3StreamTransfer(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, 2754 PAC97STREAMR3 pStreamCC, uint32_t cbToProcessMax, bool fWriteSilence, bool fInput) 2755 { 2756 if (!cbToProcessMax) 2757 return VINF_SUCCESS; 2758 2759 #ifdef VBOX_STRICT 2760 const unsigned cbFrame = PDMAudioPropsBytesPerFrame(&pStreamCC->State.Cfg.Props); 2761 #endif 2762 2763 /* Make sure to only process an integer number of audio frames. */ 2764 Assert(cbToProcessMax % cbFrame == 0); 2765 2766 ichac97R3StreamLock(pStreamCC); 2767 2768 PAC97BMREGS pRegs = &pStream->Regs; 2769 2770 if (pRegs->sr & AC97_SR_DCH) /* Controller halted? */ 2771 { 2772 if (pRegs->cr & AC97_CR_RPBM) /* Bus master operation starts. */ 2773 { 2774 switch (pStream->u8SD) 2775 { 2776 case AC97SOUNDSOURCE_PO_INDEX: 2777 /*ichac97R3WriteBUP(pThis, cbToProcess);*/ 2778 break; 2779 2780 default: 2781 break; 2782 } 2783 } 2784 2785 ichac97R3StreamUnlock(pStreamCC); 2786 return VINF_SUCCESS; 2787 } 2788 2789 /* BCIS flag still set? Skip iteration. */ 2790 if (pRegs->sr & AC97_SR_BCIS) 2791 { 2792 Log3Func(("[SD%RU8] BCIS set\n", pStream->u8SD)); 2793 2794 ichac97R3StreamUnlock(pStreamCC); 2795 return VINF_SUCCESS; 2796 } 2797 2798 uint32_t cbLeft = RT_MIN((uint32_t)(pRegs->picb << 1), cbToProcessMax); /** @todo r=andy Assumes 16bit samples. */ 2799 uint32_t cbProcessedTotal = 0; 2800 2801 PRTCIRCBUF pCircBuf = pStreamCC->State.pCircBuf; 2802 AssertPtr(pCircBuf); 2803 2804 int rc = VINF_SUCCESS; 2805 2806 Log3Func(("[SD%RU8] cbToProcessMax=%RU32, cbLeft=%RU32\n", pStream->u8SD, cbToProcessMax, cbLeft)); 2807 2808 while (cbLeft) 2809 { 2810 if (!pRegs->picb) /* Got a new buffer descriptor, that is, the position is 0? */ 2811 { 2812 Log3Func(("Fresh buffer descriptor %RU8 is empty, addr=%#x, len=%#x, skipping\n", 2813 pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len)); 2814 if (pRegs->civ == pRegs->lvi) 2815 { 2816 pRegs->sr |= AC97_SR_DCH; /** @todo r=andy Also set CELV? */ 2817 pThis->bup_flag = 0; 2818 2819 rc = VINF_EOF; 2820 break; 2821 } 2822 2823 pRegs->sr &= ~AC97_SR_CELV; 2824 if (ichac97R3StreamFetchNextBdle(pDevIns, pStream, pStreamCC)) 2825 ichac97StreamUpdateSR(pDevIns, pThis, pStream, pRegs->sr | AC97_SR_BCIS); 2826 continue; 2827 } 2828 2829 uint32_t cbChunk = cbLeft; 2830 2831 /* 2832 * Output. 2833 */ 2834 if (!fInput) 2835 { 2836 void *pvDst = NULL; 2837 size_t cbDst = 0; 2838 RTCircBufAcquireWriteBlock(pCircBuf, cbChunk, &pvDst, &cbDst); 2839 2840 if (cbDst) 2841 { 2842 int rc2 = PDMDevHlpPCIPhysRead(pDevIns, pRegs->bd.addr, pvDst, cbDst); 2843 AssertRC(rc2); 2844 2845 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled)) 2846 { /* likely */ } 2847 else 2848 AudioHlpFileWrite(pStreamCC->Dbg.Runtime.pFileDMA, pvDst, cbDst, 0 /* fFlags */); 2849 } 2850 2851 RTCircBufReleaseWriteBlock(pCircBuf, cbDst); 2852 2853 cbChunk = (uint32_t)cbDst; /* Update the current chunk size to what really has been written. */ 2854 } 2855 /* 2856 * Input. 2857 */ 2341 if (fEnable) 2342 { 2343 /* Reset some of the state. */ 2344 pStreamCC->State.fInputPreBuffered = false; 2345 if (pStreamCC->State.pCircBuf) 2346 RTCircBufReset(pStreamCC->State.pCircBuf); 2347 2348 /* (Re-)Open the stream if necessary. */ 2349 rc = ichac97R3StreamOpen(pDevIns, pThis, pThisCC, pStream, pStreamCC, false /* fForce */); 2350 2351 /* Re-register the update job with the AIO thread with correct sched hint. 2352 Note! We do not unregister it on disable because of draining. */ 2353 if (pStreamCC->State.fRegisteredAsyncUpdateJob) 2354 AudioMixerSinkRemoveUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC); 2355 int rc2 = AudioMixerSinkAddUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC, 2356 pStreamCC->State.Cfg.Device.cMsSchedulingHint); 2357 AssertRC(rc2); 2358 pStreamCC->State.fRegisteredAsyncUpdateJob = RT_SUCCESS(rc2) || rc2 == VERR_ALREADY_EXISTS; 2359 2360 /* Open debug files: */ 2361 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled)) 2362 { /* likely */ } 2858 2363 else 2859 2364 { 2860 if (! fWriteSilence)2365 if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileStream)) 2861 2366 { 2862 void *pvSrc = NULL; 2863 size_t cbSrc = 0; 2864 RTCircBufAcquireReadBlock(pCircBuf, cbChunk, &pvSrc, &cbSrc); 2865 2866 if (cbSrc) 2867 { 2868 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, pvSrc, cbSrc); 2869 AssertRC(rc2); 2870 2871 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled)) 2872 { /* likely */ } 2873 else 2874 AudioHlpFileWrite(pStreamCC->Dbg.Runtime.pFileDMA, pvSrc, cbSrc, 0 /* fFlags */); 2875 } 2876 2877 RTCircBufReleaseReadBlock(pCircBuf, cbSrc); 2878 2879 cbChunk = (uint32_t)cbSrc; /* Update the current chunk size to what really has been read. */ 2367 rc2 = AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileStream, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS, 2368 &pStreamCC->State.Cfg.Props); 2369 AssertRC(rc2); 2880 2370 } 2881 else 2371 2372 if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileDMA)) 2882 2373 { 2883 /* Since the format is signed 16-bit or 32-bit integer samples, we can 2884 use g_abRTZero64K as source and avoid some unnecessary bzero() work. */ 2885 cbChunk = RT_MIN(cbChunk, sizeof(g_abRTZero64K)); 2886 cbChunk = PDMAudioPropsFloorBytesToFrame(&pStreamCC->State.Cfg.Props, cbChunk); 2887 2888 int rc2 = PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, g_abRTZero64K, cbChunk); 2374 rc2 = AudioHlpFileOpen(pStreamCC->Dbg.Runtime.pFileDMA, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS, 2375 &pStreamCC->State.Cfg.Props); 2889 2376 AssertRC(rc2); 2890 2377 } 2891 2378 } 2892 2379 2893 if (cbChunk) 2894 { 2895 Assert(PDMAudioPropsIsSizeAligned(&pStreamCC->State.Cfg.Props, cbChunk)); 2896 Assert(cbChunk <= cbLeft); 2897 2898 cbProcessedTotal += cbChunk; 2899 Assert(cbProcessedTotal <= cbToProcessMax); 2900 cbLeft -= cbChunk; 2901 pRegs->picb -= (cbChunk >> 1); /** @todo r=andy Assumes 16bit samples. */ 2902 pRegs->bd.addr += cbChunk; 2903 } 2904 2905 LogFlowFunc(("[SD%RU8] cbChunk=%RU32, cbLeft=%RU32, cbTotal=%RU32, rc=%Rrc\n", 2906 pStream->u8SD, cbChunk, cbLeft, cbProcessedTotal, rc)); 2907 2908 if (!pRegs->picb) 2909 { 2910 uint32_t new_sr = pRegs->sr & ~AC97_SR_CELV; 2911 2912 if (pRegs->bd.ctl_len & AC97_BD_IOC) 2913 { 2914 new_sr |= AC97_SR_BCIS; 2915 } 2916 2917 if (pRegs->civ == pRegs->lvi) 2918 { 2919 /* Did we run out of data? */ 2920 LogFunc(("Underrun CIV (%RU8) == LVI (%RU8)\n", pRegs->civ, pRegs->lvi)); 2921 2922 new_sr |= AC97_SR_LVBCI | AC97_SR_DCH | AC97_SR_CELV; 2923 pThis->bup_flag = (pRegs->bd.ctl_len & AC97_BD_BUP) ? BUP_LAST : 0; 2924 2925 rc = VINF_EOF; 2926 } 2927 else 2928 new_sr |= ichac97R3StreamFetchNextBdle(pDevIns, pStream, pStreamCC); 2929 2930 ichac97StreamUpdateSR(pDevIns, pThis, pStream, new_sr); 2931 } 2932 2933 /* All data processed? */ 2934 if (rc == VINF_EOF) 2935 break; 2936 } 2937 2380 if (RT_SUCCESS(rc)) 2381 rc = AudioMixerSinkStart(pSink); 2382 } 2383 else 2384 { 2385 rc = ichac97R3StreamClose(pStream); 2386 if (RT_SUCCESS(rc)) 2387 rc = AudioMixerSinkDrainAndStop(pSink, 2388 pStreamCC->State.pCircBuf ? (uint32_t)RTCircBufUsed(pStreamCC->State.pCircBuf) : 0); 2389 } 2390 2391 /* Make sure to leave the lock before (eventually) starting the timer. */ 2392 AudioMixerSinkUnlock(pSink); 2938 2393 ichac97R3StreamUnlock(pStreamCC); 2939 2940 LogFlowFuncLeaveRC(rc); 2394 LogFunc(("[SD%RU8] fEnable=%RTbool, rc=%Rrc\n", pStream->u8SD, fEnable, rc)); 2941 2395 return rc; 2942 2396 } 2943 2397 2398 2399 /** 2400 * Returns whether an AC'97 stream is enabled or not. 2401 * 2402 * Only used by ichac97R3SaveExec(). 2403 * 2404 * @returns VBox status code. 2405 * @param pThisCC The ring-3 AC'97 device state. 2406 * @param pStream Stream to return status for. 2407 */ 2408 static bool ichac97R3StreamIsEnabled(PAC97STATER3 pThisCC, PAC97STREAM pStream) 2409 { 2410 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD); 2411 bool fIsEnabled = pSink && (AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING); 2412 2413 LogFunc(("[SD%RU8] fIsEnabled=%RTbool\n", pStream->u8SD, fIsEnabled)); 2414 return fIsEnabled; 2415 } 2416 2417 2418 /** 2419 * Terminates an AC'97 audio stream (VM destroy). 2420 * 2421 * This is called by ichac97R3StreamsDestroy during VM poweroff & destruction. 2422 * 2423 * @returns VBox status code. 2424 * @param pThisCC The ring-3 AC'97 state. 2425 * @param pStream The AC'97 stream to destroy (shared). 2426 * @param pStreamCC The AC'97 stream to destroy (ring-3). 2427 * @sa ichac97R3StreamCreate 2428 */ 2429 static void ichac97R3StreamDestroy(PAC97STATER3 pThisCC, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC) 2430 { 2431 LogFlowFunc(("[SD%RU8]\n", pStream->u8SD)); 2432 2433 ichac97R3StreamClose(pStream); 2434 2435 int rc2 = RTCritSectDelete(&pStreamCC->State.CritSect); 2436 AssertRC(rc2); 2437 2438 if (pStreamCC->State.fRegisteredAsyncUpdateJob) 2439 { 2440 PAUDMIXSINK pSink = ichac97R3IndexToSink(pThisCC, pStream->u8SD); 2441 if (pSink) 2442 AudioMixerSinkRemoveUpdateJob(pSink, ichac97R3StreamUpdateAsyncIoJob, pStreamCC); 2443 pStreamCC->State.fRegisteredAsyncUpdateJob = false; 2444 } 2445 2446 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled)) 2447 { /* likely */ } 2448 else 2449 { 2450 AudioHlpFileDestroy(pStreamCC->Dbg.Runtime.pFileStream); 2451 pStreamCC->Dbg.Runtime.pFileStream = NULL; 2452 2453 AudioHlpFileDestroy(pStreamCC->Dbg.Runtime.pFileDMA); 2454 pStreamCC->Dbg.Runtime.pFileDMA = NULL; 2455 } 2456 2457 if (pStreamCC->State.pCircBuf) 2458 { 2459 RTCircBufDestroy(pStreamCC->State.pCircBuf); 2460 pStreamCC->State.pCircBuf = NULL; 2461 } 2462 2463 LogFlowFuncLeave(); 2464 } 2465 2466 2467 /** 2468 * Initializes an AC'97 audio stream (VM construct). 2469 * 2470 * This is only called by ichac97R3Construct. 2471 * 2472 * @returns VBox status code. 2473 * @param pThisCC The ring-3 AC'97 state. 2474 * @param pStream The AC'97 stream to create (shared). 2475 * @param pStreamCC The AC'97 stream to create (ring-3). 2476 * @param u8SD Stream descriptor number to assign. 2477 * @sa ichac97R3StreamDestroy 2478 */ 2479 static int ichac97R3StreamCreate(PAC97STATER3 pThisCC, PAC97STREAM pStream, PAC97STREAMR3 pStreamCC, uint8_t u8SD) 2480 { 2481 LogFunc(("[SD%RU8] pStream=%p\n", u8SD, pStream)); 2482 2483 AssertReturn(u8SD < AC97_MAX_STREAMS, VERR_INVALID_PARAMETER); 2484 pStream->u8SD = u8SD; 2485 pStreamCC->u8SD = u8SD; 2486 2487 int rc = RTCritSectInit(&pStreamCC->State.CritSect); 2488 AssertRCReturn(rc, rc); 2489 2490 pStreamCC->Dbg.Runtime.fEnabled = pThisCC->Dbg.fEnabled; 2491 2492 if (RT_LIKELY(!pStreamCC->Dbg.Runtime.fEnabled)) 2493 { /* likely */ } 2494 else 2495 { 2496 char szFile[64]; 2497 2498 if (ichac97R3GetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN) 2499 RTStrPrintf(szFile, sizeof(szFile), "ac97StreamWriteSD%RU8", pStream->u8SD); 2500 else 2501 RTStrPrintf(szFile, sizeof(szFile), "ac97StreamReadSD%RU8", pStream->u8SD); 2502 2503 char szPath[RTPATH_MAX]; 2504 int rc2 = AudioHlpFileNameGet(szPath, sizeof(szPath), pThisCC->Dbg.pszOutPath, szFile, 2505 0 /* uInst */, AUDIOHLPFILETYPE_WAV, AUDIOHLPFILENAME_FLAGS_NONE); 2506 AssertRC(rc2); 2507 rc2 = AudioHlpFileCreate(AUDIOHLPFILETYPE_WAV, szPath, AUDIOHLPFILE_FLAGS_NONE, &pStreamCC->Dbg.Runtime.pFileStream); 2508 AssertRC(rc2); 2509 2510 if (ichac97R3GetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN) 2511 RTStrPrintf(szFile, sizeof(szFile), "ac97DMAWriteSD%RU8", pStream->u8SD); 2512 else 2513 RTStrPrintf(szFile, sizeof(szFile), "ac97DMAReadSD%RU8", pStream->u8SD); 2514 2515 rc2 = AudioHlpFileNameGet(szPath, sizeof(szPath), pThisCC->Dbg.pszOutPath, szFile, 2516 0 /* uInst */, AUDIOHLPFILETYPE_WAV, AUDIOHLPFILENAME_FLAGS_NONE); 2517 AssertRC(rc2); 2518 2519 rc2 = AudioHlpFileCreate(AUDIOHLPFILETYPE_WAV, szPath, AUDIOHLPFILE_FLAGS_NONE, &pStreamCC->Dbg.Runtime.pFileDMA); 2520 AssertRC(rc2); 2521 2522 /* Delete stale debugging files from a former run. */ 2523 AudioHlpFileDelete(pStreamCC->Dbg.Runtime.pFileStream); 2524 AudioHlpFileDelete(pStreamCC->Dbg.Runtime.pFileDMA); 2525 } 2526 2527 return rc; 2528 } 2529 2944 2530 #endif /* IN_RING3 */ 2945 2531 2532 2533 /********************************************************************************************************************************* 2534 * NABM I/O Port Handlers (Global + Stream) * 2535 *********************************************************************************************************************************/ 2946 2536 2947 2537 /** … … 3120 2710 } 3121 2711 2712 3122 2713 /** 3123 2714 * @callback_method_impl{FNIOMIOPORTNEWOUT} … … 3321 2912 return rc; 3322 2913 } 2914 2915 2916 /********************************************************************************************************************************* 2917 * Mixer & NAM I/O handlers * 2918 *********************************************************************************************************************************/ 2919 2920 /** 2921 * Sets a AC'97 mixer control to a specific value. 2922 * 2923 * @returns VBox status code. 2924 * @param pThis The shared AC'97 state. 2925 * @param uMixerIdx Mixer control to set value for. 2926 * @param uVal Value to set. 2927 */ 2928 static void ichac97MixerSet(PAC97STATE pThis, uint8_t uMixerIdx, uint16_t uVal) 2929 { 2930 AssertMsgReturnVoid(uMixerIdx + 2U <= sizeof(pThis->mixer_data), 2931 ("Index %RU8 out of bounds (%zu)\n", uMixerIdx, sizeof(pThis->mixer_data))); 2932 2933 LogRel2(("AC97: Setting mixer index #%RU8 to %RU16 (%RU8 %RU8)\n", 2934 uMixerIdx, uVal, RT_HI_U8(uVal), RT_LO_U8(uVal))); 2935 2936 pThis->mixer_data[uMixerIdx + 0] = RT_LO_U8(uVal); 2937 pThis->mixer_data[uMixerIdx + 1] = RT_HI_U8(uVal); 2938 } 2939 2940 2941 /** 2942 * Gets a value from a specific AC'97 mixer control. 2943 * 2944 * @returns Retrieved mixer control value. 2945 * @param pThis The shared AC'97 state. 2946 * @param uMixerIdx Mixer control to get value for. 2947 */ 2948 static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t uMixerIdx) 2949 { 2950 AssertMsgReturn(uMixerIdx + 2U <= sizeof(pThis->mixer_data), 2951 ("Index %RU8 out of bounds (%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)), 2952 UINT16_MAX); 2953 return RT_MAKE_U16(pThis->mixer_data[uMixerIdx + 0], pThis->mixer_data[uMixerIdx + 1]); 2954 } 2955 2956 #ifdef IN_RING3 2957 2958 /** 2959 * Sets the volume of a specific AC'97 mixer control. 2960 * 2961 * This currently only supports attenuation -- gain support is currently not implemented. 2962 * 2963 * @returns VBox status code. 2964 * @param pThis The shared AC'97 state. 2965 * @param pThisCC The ring-3 AC'97 state. 2966 * @param index AC'97 mixer index to set volume for. 2967 * @param enmMixerCtl Corresponding audio mixer sink. 2968 * @param uVal Volume value to set. 2969 */ 2970 static int ichac97R3MixerSetVolume(PAC97STATE pThis, PAC97STATER3 pThisCC, int index, PDMAUDIOMIXERCTL enmMixerCtl, uint32_t uVal) 2971 { 2972 /* 2973 * From AC'97 SoundMax Codec AD1981A/AD1981B: 2974 * "Because AC '97 defines 6-bit volume registers, to maintain compatibility whenever the 2975 * D5 or D13 bits are set to 1, their respective lower five volume bits are automatically 2976 * set to 1 by the Codec logic. On readback, all lower 5 bits will read ones whenever 2977 * these bits are set to 1." 2978 * 2979 * Linux ALSA depends on this behavior to detect that only 5 bits are used for volume 2980 * control and the optional 6th bit is not used. Note that this logic only applies to the 2981 * master volume controls. 2982 */ 2983 if (index == AC97_Master_Volume_Mute || index == AC97_Headphone_Volume_Mute || index == AC97_Master_Volume_Mono_Mute) 2984 { 2985 if (uVal & RT_BIT(5)) /* D5 bit set? */ 2986 uVal |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0); 2987 if (uVal & RT_BIT(13)) /* D13 bit set? */ 2988 uVal |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8); 2989 } 2990 2991 const bool fCtlMuted = (uVal >> AC97_BARS_VOL_MUTE_SHIFT) & 1; 2992 uint8_t uCtlAttLeft = (uVal >> 8) & AC97_BARS_VOL_MASK; 2993 uint8_t uCtlAttRight = uVal & AC97_BARS_VOL_MASK; 2994 2995 /* For the master and headphone volume, 0 corresponds to 0dB attenuation. For the other 2996 * volume controls, 0 means 12dB gain and 8 means unity gain. 2997 */ 2998 if (index != AC97_Master_Volume_Mute && index != AC97_Headphone_Volume_Mute) 2999 { 3000 # ifndef VBOX_WITH_AC97_GAIN_SUPPORT 3001 /* NB: Currently there is no gain support, only attenuation. */ 3002 uCtlAttLeft = uCtlAttLeft < 8 ? 0 : uCtlAttLeft - 8; 3003 uCtlAttRight = uCtlAttRight < 8 ? 0 : uCtlAttRight - 8; 3004 # endif 3005 } 3006 Assert(uCtlAttLeft <= 255 / AC97_DB_FACTOR); 3007 Assert(uCtlAttRight <= 255 / AC97_DB_FACTOR); 3008 3009 LogFunc(("index=0x%x, uVal=%RU32, enmMixerCtl=%RU32\n", index, uVal, enmMixerCtl)); 3010 LogFunc(("uCtlAttLeft=%RU8, uCtlAttRight=%RU8 ", uCtlAttLeft, uCtlAttRight)); 3011 3012 /* 3013 * For AC'97 volume controls, each additional step means -1.5dB attenuation with 3014 * zero being maximum. In contrast, we're internally using 255 (PDMAUDIO_VOLUME_MAX) 3015 * steps, each -0.375dB, where 0 corresponds to -96dB and 255 corresponds to 0dB. 3016 */ 3017 uint8_t lVol = PDMAUDIO_VOLUME_MAX - uCtlAttLeft * AC97_DB_FACTOR; 3018 uint8_t rVol = PDMAUDIO_VOLUME_MAX - uCtlAttRight * AC97_DB_FACTOR; 3019 3020 Log(("-> fMuted=%RTbool, lVol=%RU8, rVol=%RU8\n", fCtlMuted, lVol, rVol)); 3021 3022 int rc = VINF_SUCCESS; 3023 3024 if (pThisCC->pMixer) /* Device can be in reset state, so no mixer available. */ 3025 { 3026 PDMAUDIOVOLUME Vol = { fCtlMuted, lVol, rVol }; 3027 PAUDMIXSINK pSink = NULL; 3028 3029 switch (enmMixerCtl) 3030 { 3031 case PDMAUDIOMIXERCTL_VOLUME_MASTER: 3032 rc = AudioMixerSetMasterVolume(pThisCC->pMixer, &Vol); 3033 break; 3034 3035 case PDMAUDIOMIXERCTL_FRONT: 3036 pSink = pThisCC->pSinkOut; 3037 break; 3038 3039 case PDMAUDIOMIXERCTL_MIC_IN: 3040 case PDMAUDIOMIXERCTL_LINE_IN: 3041 /* These are recognized but do nothing. */ 3042 break; 3043 3044 default: 3045 AssertFailed(); 3046 rc = VERR_NOT_SUPPORTED; 3047 break; 3048 } 3049 3050 if (pSink) 3051 rc = AudioMixerSinkSetVolume(pSink, &Vol); 3052 } 3053 3054 ichac97MixerSet(pThis, index, uVal); 3055 3056 if (RT_FAILURE(rc)) 3057 LogFlowFunc(("Failed with %Rrc\n", rc)); 3058 3059 return rc; 3060 } 3061 3062 /** 3063 * Sets the gain of a specific AC'97 recording control. 3064 * 3065 * NB: gain support is currently not implemented in PDM audio. 3066 * 3067 * @returns VBox status code. 3068 * @param pThis The shared AC'97 state. 3069 * @param pThisCC The ring-3 AC'97 state. 3070 * @param index AC'97 mixer index to set volume for. 3071 * @param enmMixerCtl Corresponding audio mixer sink. 3072 * @param uVal Volume value to set. 3073 */ 3074 static int ichac97R3MixerSetGain(PAC97STATE pThis, PAC97STATER3 pThisCC, int index, PDMAUDIOMIXERCTL enmMixerCtl, uint32_t uVal) 3075 { 3076 /* 3077 * For AC'97 recording controls, each additional step means +1.5dB gain with 3078 * zero being 0dB gain and 15 being +22.5dB gain. 3079 */ 3080 const bool fCtlMuted = (uVal >> AC97_BARS_VOL_MUTE_SHIFT) & 1; 3081 uint8_t uCtlGainLeft = (uVal >> 8) & AC97_BARS_GAIN_MASK; 3082 uint8_t uCtlGainRight = uVal & AC97_BARS_GAIN_MASK; 3083 3084 Assert(uCtlGainLeft <= 255 / AC97_DB_FACTOR); 3085 Assert(uCtlGainRight <= 255 / AC97_DB_FACTOR); 3086 3087 LogFunc(("index=0x%x, uVal=%RU32, enmMixerCtl=%RU32\n", index, uVal, enmMixerCtl)); 3088 LogFunc(("uCtlGainLeft=%RU8, uCtlGainRight=%RU8 ", uCtlGainLeft, uCtlGainRight)); 3089 3090 uint8_t lVol = PDMAUDIO_VOLUME_MAX + uCtlGainLeft * AC97_DB_FACTOR; 3091 uint8_t rVol = PDMAUDIO_VOLUME_MAX + uCtlGainRight * AC97_DB_FACTOR; 3092 3093 /* We do not currently support gain. Since AC'97 does not support attenuation 3094 * for the recording input, the best we can do is set the maximum volume. 3095 */ 3096 # ifndef VBOX_WITH_AC97_GAIN_SUPPORT 3097 /* NB: Currently there is no gain support, only attenuation. Since AC'97 does not 3098 * support attenuation for the recording inputs, the best we can do is set the 3099 * maximum volume. 3100 */ 3101 lVol = rVol = PDMAUDIO_VOLUME_MAX; 3102 # endif 3103 3104 Log(("-> fMuted=%RTbool, lVol=%RU8, rVol=%RU8\n", fCtlMuted, lVol, rVol)); 3105 3106 int rc = VINF_SUCCESS; 3107 3108 if (pThisCC->pMixer) /* Device can be in reset state, so no mixer available. */ 3109 { 3110 PDMAUDIOVOLUME Vol = { fCtlMuted, lVol, rVol }; 3111 PAUDMIXSINK pSink = NULL; 3112 3113 switch (enmMixerCtl) 3114 { 3115 case PDMAUDIOMIXERCTL_MIC_IN: 3116 pSink = pThisCC->pSinkMicIn; 3117 break; 3118 3119 case PDMAUDIOMIXERCTL_LINE_IN: 3120 pSink = pThisCC->pSinkLineIn; 3121 break; 3122 3123 default: 3124 AssertFailed(); 3125 rc = VERR_NOT_SUPPORTED; 3126 break; 3127 } 3128 3129 if (pSink) { 3130 rc = AudioMixerSinkSetVolume(pSink, &Vol); 3131 /* There is only one AC'97 recording gain control. If line in 3132 * is changed, also update the microphone. If the optional dedicated 3133 * microphone is changed, only change that. 3134 * NB: The codecs we support do not have the dedicated microphone control. 3135 */ 3136 if ((pSink == pThisCC->pSinkLineIn) && pThisCC->pSinkMicIn) 3137 rc = AudioMixerSinkSetVolume(pSink, &Vol); 3138 } 3139 } 3140 3141 ichac97MixerSet(pThis, index, uVal); 3142 3143 if (RT_FAILURE(rc)) 3144 LogFlowFunc(("Failed with %Rrc\n", rc)); 3145 3146 return rc; 3147 } 3148 3149 /** 3150 * Converts an AC'97 recording source index to a PDM audio recording source. 3151 * 3152 * @returns PDM audio recording source. 3153 * @param uIdx AC'97 index to convert. 3154 */ 3155 static PDMAUDIOPATH ichac97R3IdxToRecSource(uint8_t uIdx) 3156 { 3157 switch (uIdx) 3158 { 3159 case AC97_REC_MIC: return PDMAUDIOPATH_IN_MIC; 3160 case AC97_REC_CD: return PDMAUDIOPATH_IN_CD; 3161 case AC97_REC_VIDEO: return PDMAUDIOPATH_IN_VIDEO; 3162 case AC97_REC_AUX: return PDMAUDIOPATH_IN_AUX; 3163 case AC97_REC_LINE_IN: return PDMAUDIOPATH_IN_LINE; 3164 case AC97_REC_PHONE: return PDMAUDIOPATH_IN_PHONE; 3165 default: 3166 break; 3167 } 3168 3169 LogFlowFunc(("Unknown record source %d, using MIC\n", uIdx)); 3170 return PDMAUDIOPATH_IN_MIC; 3171 } 3172 3173 /** 3174 * Converts a PDM audio recording source to an AC'97 recording source index. 3175 * 3176 * @returns AC'97 recording source index. 3177 * @param enmRecSrc PDM audio recording source to convert. 3178 */ 3179 static uint8_t ichac97R3RecSourceToIdx(PDMAUDIOPATH enmRecSrc) 3180 { 3181 switch (enmRecSrc) 3182 { 3183 case PDMAUDIOPATH_IN_MIC: return AC97_REC_MIC; 3184 case PDMAUDIOPATH_IN_CD: return AC97_REC_CD; 3185 case PDMAUDIOPATH_IN_VIDEO: return AC97_REC_VIDEO; 3186 case PDMAUDIOPATH_IN_AUX: return AC97_REC_AUX; 3187 case PDMAUDIOPATH_IN_LINE: return AC97_REC_LINE_IN; 3188 case PDMAUDIOPATH_IN_PHONE: return AC97_REC_PHONE; 3189 default: 3190 AssertMsgFailedBreak(("%d\n", enmRecSrc)); 3191 } 3192 3193 LogFlowFunc(("Unknown audio recording source %d using MIC\n", enmRecSrc)); 3194 return AC97_REC_MIC; 3195 } 3196 3197 3198 /** 3199 * Performs an AC'97 mixer record select to switch to a different recording 3200 * source. 3201 * 3202 * @param pThis The shared AC'97 state. 3203 * @param val AC'97 recording source index to set. 3204 */ 3205 static void ichac97R3MixerRecordSelect(PAC97STATE pThis, uint32_t val) 3206 { 3207 uint8_t rs = val & AC97_REC_MASK; 3208 uint8_t ls = (val >> 8) & AC97_REC_MASK; 3209 3210 PDMAUDIOPATH const ars = ichac97R3IdxToRecSource(rs); 3211 PDMAUDIOPATH const als = ichac97R3IdxToRecSource(ls); 3212 3213 rs = ichac97R3RecSourceToIdx(ars); 3214 ls = ichac97R3RecSourceToIdx(als); 3215 3216 LogRel(("AC97: Record select to left=%s, right=%s\n", PDMAudioPathGetName(ars), PDMAudioPathGetName(als))); 3217 3218 ichac97MixerSet(pThis, AC97_Record_Select, rs | (ls << 8)); 3219 } 3220 3221 /** 3222 * Resets the AC'97 mixer. 3223 * 3224 * @returns VBox status code. 3225 * @param pThis The shared AC'97 state. 3226 * @param pThisCC The ring-3 AC'97 state. 3227 */ 3228 static int ichac97R3MixerReset(PAC97STATE pThis, PAC97STATER3 pThisCC) 3229 { 3230 LogFlowFuncEnter(); 3231 3232 RT_ZERO(pThis->mixer_data); 3233 3234 /* Note: Make sure to reset all registers first before bailing out on error. */ 3235 3236 ichac97MixerSet(pThis, AC97_Reset , 0x0000); /* 6940 */ 3237 ichac97MixerSet(pThis, AC97_Master_Volume_Mono_Mute , 0x8000); 3238 ichac97MixerSet(pThis, AC97_PC_BEEP_Volume_Mute , 0x0000); 3239 3240 ichac97MixerSet(pThis, AC97_Phone_Volume_Mute , 0x8008); 3241 ichac97MixerSet(pThis, AC97_Mic_Volume_Mute , 0x8008); 3242 ichac97MixerSet(pThis, AC97_CD_Volume_Mute , 0x8808); 3243 ichac97MixerSet(pThis, AC97_Aux_Volume_Mute , 0x8808); 3244 ichac97MixerSet(pThis, AC97_Record_Gain_Mic_Mute , 0x8000); 3245 ichac97MixerSet(pThis, AC97_General_Purpose , 0x0000); 3246 ichac97MixerSet(pThis, AC97_3D_Control , 0x0000); 3247 ichac97MixerSet(pThis, AC97_Powerdown_Ctrl_Stat , 0x000f); 3248 3249 /* Configure Extended Audio ID (EAID) + Control & Status (EACS) registers. */ 3250 const uint16_t fEAID = AC97_EAID_REV1 | AC97_EACS_VRA | AC97_EACS_VRM; /* Our hardware is AC'97 rev2.3 compliant. */ 3251 const uint16_t fEACS = AC97_EACS_VRA | AC97_EACS_VRM; /* Variable Rate PCM Audio (VRA) + Mic-In (VRM) capable. */ 3252 3253 LogRel(("AC97: Mixer reset (EAID=0x%x, EACS=0x%x)\n", fEAID, fEACS)); 3254 3255 ichac97MixerSet(pThis, AC97_Extended_Audio_ID, fEAID); 3256 ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, fEACS); 3257 ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate , 0xbb80 /* 48000 Hz by default */); 3258 ichac97MixerSet(pThis, AC97_PCM_Surround_DAC_Rate , 0xbb80 /* 48000 Hz by default */); 3259 ichac97MixerSet(pThis, AC97_PCM_LFE_DAC_Rate , 0xbb80 /* 48000 Hz by default */); 3260 ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate , 0xbb80 /* 48000 Hz by default */); 3261 ichac97MixerSet(pThis, AC97_MIC_ADC_Rate , 0xbb80 /* 48000 Hz by default */); 3262 3263 if (pThis->enmCodecModel == AC97CODEC_AD1980) 3264 { 3265 /* Analog Devices 1980 (AD1980) */ 3266 ichac97MixerSet(pThis, AC97_Reset , 0x0010); /* Headphones. */ 3267 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144); 3268 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5370); 3269 ichac97MixerSet(pThis, AC97_Headphone_Volume_Mute , 0x8000); 3270 } 3271 else if (pThis->enmCodecModel == AC97CODEC_AD1981B) 3272 { 3273 /* Analog Devices 1981B (AD1981B) */ 3274 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144); 3275 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5374); 3276 } 3277 else 3278 { 3279 /* Sigmatel 9700 (STAC9700) */ 3280 ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x8384); 3281 ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x7600); /* 7608 */ 3282 } 3283 ichac97R3MixerRecordSelect(pThis, 0); 3284 3285 /* The default value is 8000h, which corresponds to 0 dB attenuation with mute on. */ 3286 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER, 0x8000); 3287 3288 /* The default value for stereo registers is 8808h, which corresponds to 0 dB gain with mute on.*/ 3289 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT, 0x8808); 3290 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808); 3291 ichac97R3MixerSetVolume(pThis, pThisCC, AC97_Mic_Volume_Mute, PDMAUDIOMIXERCTL_MIC_IN, 0x8008); 3292 3293 /* The default for record controls is 0 dB gain with mute on. */ 3294 ichac97R3MixerSetGain(pThis, pThisCC, AC97_Record_Gain_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8000); 3295 ichac97R3MixerSetGain(pThis, pThisCC, AC97_Record_Gain_Mic_Mute, PDMAUDIOMIXERCTL_MIC_IN, 0x8000); 3296 3297 return VINF_SUCCESS; 3298 } 3299 3300 #endif /* IN_RING3 */ 3323 3301 3324 3302 /** … … 3933 3911 3934 3912 /** 3913 * Destroys all AC'97 audio streams of the device. 3914 * 3915 * @param pDevIns The device AC'97 instance. 3916 * @param pThis The shared AC'97 state. 3917 * @param pThisCC The ring-3 AC'97 state. 3918 */ 3919 static void ichac97R3StreamsDestroy(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC) 3920 { 3921 LogFlowFuncEnter(); 3922 3923 /* 3924 * Destroy all AC'97 streams. 3925 */ 3926 for (unsigned i = 0; i < AC97_MAX_STREAMS; i++) 3927 ichac97R3StreamDestroy(pThisCC, &pThis->aStreams[i], &pThisCC->aStreams[i]); 3928 3929 /* 3930 * Destroy all sinks. 3931 */ 3932 if (pThisCC->pSinkLineIn) 3933 { 3934 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pThisCC->pSinkLineIn, PDMAUDIODIR_IN, PDMAUDIOPATH_IN_LINE); 3935 3936 AudioMixerSinkDestroy(pThisCC->pSinkLineIn, pDevIns); 3937 pThisCC->pSinkLineIn = NULL; 3938 } 3939 3940 if (pThisCC->pSinkMicIn) 3941 { 3942 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pThisCC->pSinkMicIn, PDMAUDIODIR_IN, PDMAUDIOPATH_IN_MIC); 3943 3944 AudioMixerSinkDestroy(pThisCC->pSinkMicIn, pDevIns); 3945 pThisCC->pSinkMicIn = NULL; 3946 } 3947 3948 if (pThisCC->pSinkOut) 3949 { 3950 ichac97R3MixerRemoveDrvStreams(pDevIns, pThisCC, pThisCC->pSinkOut, PDMAUDIODIR_OUT, PDMAUDIOPATH_OUT_FRONT); 3951 3952 AudioMixerSinkDestroy(pThisCC->pSinkOut, pDevIns); 3953 pThisCC->pSinkOut = NULL; 3954 } 3955 } 3956 3957 3958 /** 3935 3959 * Powers off the device. 3936 3960 * … … 4439 4463 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowProblems, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, 4440 4464 "Number of internal DMA buffer problems.", "Stream%u/DMABufferProblems", idxStream); 4441 if (ichac97 GetDirFromSD(idxStream) == PDMAUDIODIR_OUT)4465 if (ichac97R3GetDirFromSD(idxStream) == PDMAUDIODIR_OUT) 4442 4466 PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, 4443 4467 "Number of internal DMA buffer overflows.", "Stream%u/DMABufferOverflows", idxStream);
Note:
See TracChangeset
for help on using the changeset viewer.