VirtualBox

Changeset 89721 in vbox


Ignore:
Timestamp:
Jun 15, 2021 7:03:40 PM (3 years ago)
Author:
vboxsync
Message:

DevIchAc97: Tried to organized the functions a bit more logically. No functional changes. bugref:9890

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DevIchAc97.cpp

    r89715 r89721  
    679679*   Internal Functions                                                                                                           *
    680680*********************************************************************************************************************************/
     681static void                 ichac97StreamUpdateSR(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream, uint32_t new_sr);
     682static uint16_t             ichac97MixerGet(PAC97STATE pThis, uint32_t uMixerIdx);
    681683#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 */
     684static void                 ichac97R3StreamLock(PAC97STREAMR3 pStreamCC);
     685static void                 ichac97R3StreamUnlock(PAC97STREAMR3 pStreamCC);
     686
     687static void                 ichac97R3DbgPrintBdl(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STREAM pStream,
     688                                                 PCDBGFINFOHLP pHlp, const char *pszPrefix);
     689static DECLCALLBACK(void)   ichac97R3Reset(PPDMDEVINS pDevIns);
     690#endif
    705691
    706692
     
    814800
    815801/**
     802 * Returns the audio direction of a specified stream descriptor.
     803 *
     804 * @return  Audio direction.
     805 */
     806DECLINLINE(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/**
    816821 * Retrieves the audio mixer sink of a corresponding AC'97 stream index.
    817822 *
     
    831836    }
    832837}
     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 */
     850static 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 */
     864static 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 */
     873static 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
    833913
    834914/**
     
    911991}
    912992
    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.
    9181004 * @param   pDevIns             The device instance.
    9191005 * @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 */
     1014static 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. */
    9371034        {
    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            }
    9401044        }
    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? */
    9421072        {
    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;
    9451088        }
    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)
    9471096        {
    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. */
    9501115        }
    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         */
    10501119        else
    10511120        {
    1052             if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileStream))
     1121            if (!fWriteSilence)
    10531122            {
    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. */
    10571141            }
    1058 
    1059             if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileDMA))
     1142            else
    10601143            {
    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);
    10631150                AssertRC(rc2);
    10641151            }
    10651152        }
    10661153
    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
    10801199    ichac97R3StreamUnlock(pStreamCC);
    1081     LogFunc(("[SD%RU8] fEnable=%RTbool, rc=%Rrc\n", pStream->u8SD, fEnable, rc));
     1200
     1201    LogFlowFuncLeaveRC(rc);
    10821202    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     else
    1142     {
    1143         char szFile[64];
    1144 
    1145         if (ichac97GetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)
    1146             RTStrPrintf(szFile, sizeof(szFile), "ac97StreamWriteSD%RU8", pStream->u8SD);
    1147         else
    1148             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         else
    1160             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     else
    1205     {
    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     }
    12651203}
    12661204
     
    12751213static void ichac97R3StreamPullFromMixer(PAC97STREAMR3 pStreamR3, PAUDMIXSINK pSink)
    12761214{
    1277 #ifdef LOG_ENABLED
     1215# ifdef LOG_ENABLED
    12781216    uint64_t const offWriteOld = pStreamR3->State.offWrite;
    1279 #endif
     1217# endif
    12801218    pStreamR3->State.offWrite = AudioMixerSinkTransferToCircBuf(pSink,
    12811219                                                                pStreamR3->State.pCircBuf,
     
    13011239static void ichac97R3StreamPushToMixer(PAC97STREAMR3 pStreamR3, PAUDMIXSINK pSink)
    13021240{
    1303 #ifdef LOG_ENABLED
     1241# ifdef LOG_ENABLED
    13041242    uint64_t const offReadOld = pStreamR3->State.offRead;
    1305 #endif
     1243# endif
    13061244    pStreamR3->State.offRead = AudioMixerSinkTransferFromCircBuf(pSink,
    13071245                                                                 pStreamR3->State.pCircBuf,
     
    13311269 * @param   pStream             The AC'97 stream to update (shared).
    13321270 * @param   pStreamCC           The AC'97 stream to update (ring-3).
     1271 * @param   pSink               The sink being updated.
    13331272 */
    13341273static void ichac97R3StreamUpdateDma(PPDMDEVINS pDevIns, PAC97STATE pThis, PAC97STATER3 pThisCC,
     
    15661505}
    15671506
     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 */
     1515static 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 */
     1571DECLINLINE(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 */
     1582static 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
    15681607#endif /* IN_RING3 */
    15691608
    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.
    15721617 *
    15731618 * @returns VBox status code.
     1619 * @param   pStreamCC           The AC'97 stream to lock (ring-3).
     1620 */
     1621static 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 */
     1633static 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.
    15741645 * @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 */
     1649static 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 */
     1706static 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 *
    15941721 * @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 */
     1725static 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}
    16061749
    16071750/**
     
    16671810    AssertPtrReturn(pMixSink, VERR_INVALID_POINTER);
    16681811
    1669     PPDMAUDIOSTREAMCFG pStreamCfg = PDMAudioStrmCfgDup(pCfg);
     1812    PPDMAUDIOSTREAMCFG pStreamCfg = PDMAudioStrmCfgDup(pCfg); /** @todo r=bird: This seems kind of pointless... */
    16701813    if (!pStreamCfg)
    16711814        return VERR_NO_MEMORY;
     
    18531996    {
    18541997        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, in
    1872      * 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 we
    1874      * probably cannot look ahead without violating that restriction.  This is
    1875      * 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 stereo
    1882          * prevents 0xffff), which translates to 743ms at a 44.1kHz rate, we must
    1883          * also take the nominal timer frequency into account here so we keep
    1884          * moving data at a steady rate.  (In theory, I think the guest can even
    1885          * set up just one buffer and anticipate where we are in the buffer
    1886          * processing when it writes/reads from it.  Linux seems to be doing such
    1887          * 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         else
    1897             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));
    19091998    }
    19101999}
     
    22292318}
    22302319
    2231 /**
    2232  * Locks an AC'97 stream for serialized access.
     2320
     2321/**
     2322 * Enables or disables an AC'97 audio stream.
    22332323 *
    22342324 * @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 */
     2333static 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);
    23462339
    23472340    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 */ }
    28582363        else
    28592364        {
    2860             if (!fWriteSilence)
     2365            if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileStream))
    28612366            {
    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);
    28802370            }
    2881             else
     2371
     2372            if (!AudioHlpFileIsOpen(pStreamCC->Dbg.Runtime.pFileDMA))
    28822373            {
    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);
    28892376                AssertRC(rc2);
    28902377            }
    28912378        }
    28922379
    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);
    29382393    ichac97R3StreamUnlock(pStreamCC);
    2939 
    2940     LogFlowFuncLeaveRC(rc);
     2394    LogFunc(("[SD%RU8] fEnable=%RTbool, rc=%Rrc\n", pStream->u8SD, fEnable, rc));
    29412395    return rc;
    29422396}
    29432397
     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 */
     2408static 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 */
     2429static 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 */
     2479static 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
    29442530#endif /* IN_RING3 */
    29452531
     2532
     2533/*********************************************************************************************************************************
     2534*   NABM I/O Port Handlers (Global + Stream)                                                                                     *
     2535*********************************************************************************************************************************/
    29462536
    29472537/**
     
    31202710}
    31212711
     2712
    31222713/**
    31232714 * @callback_method_impl{FNIOMIOPORTNEWOUT}
     
    33212912    return rc;
    33222913}
     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 */
     2928static 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 */
     2948static 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 */
     2970static 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 */
     3074static 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 */
     3155static 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 */
     3179static 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 */
     3205static 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 */
     3228static 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 */
    33233301
    33243302/**
     
    39333911
    39343912/**
     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 */
     3919static 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/**
    39353959 * Powers off the device.
    39363960 *
     
    44394463        PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowProblems, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
    44404464                               "Number of internal DMA buffer problems.",   "Stream%u/DMABufferProblems", idxStream);
    4441         if (ichac97GetDirFromSD(idxStream) == PDMAUDIODIR_OUT)
     4465        if (ichac97R3GetDirFromSD(idxStream) == PDMAUDIODIR_OUT)
    44424466            PDMDevHlpSTAMRegisterF(pDevIns, &pThisCC->aStreams[idxStream].State.StatDmaFlowErrors, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES,
    44434467                                   "Number of internal DMA buffer overflows.",  "Stream%u/DMABufferOverflows", idxStream);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette