VirtualBox

儲存庫 vbox 的更動 67533


忽略:
時間撮記:
2017-6-21 上午09:47:08 (7 年 以前)
作者:
vboxsync
訊息:

Audio/DevHDA.cpp: Fixed audio handling when restoring from a saved state. Split up the initialization / reset logic in more fine-grained pieces to better reuse those.

位置:
trunk/src/VBox/Devices
檔案:
修改 2 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/Devices/Audio/DevHDA.cpp

    r67508 r67533  
    930930    HDAMIXERSINK                       SinkMicIn;
    931931#endif
    932     /** The controller's base time stamp which the WALCLK register
    933      *  derives its current value from. */
    934     uint64_t                           u64BaseTS;
    935932    /** Last updated WALCLK counter. */
    936933    uint64_t                           u64WalClk;
     
    13131310    SSMFIELD_ENTRY_TERM()
    13141311};
     1312
     1313/** HDASTREAMPERIOD field descriptors for the v7 saved state. */
     1314static SSMFIELD const g_aSSMStreamPeriodFields7[] =
     1315{
     1316    SSMFIELD_ENTRY(HDASTREAMPERIOD, u64StartWalClk),
     1317    SSMFIELD_ENTRY(HDASTREAMPERIOD, u64ElapsedWalClk),
     1318    SSMFIELD_ENTRY(HDASTREAMPERIOD, framesTransferred),
     1319    SSMFIELD_ENTRY(HDASTREAMPERIOD, cIntPending),
     1320    SSMFIELD_ENTRY_TERM()
     1321};
    13151322#endif
    13161323
     
    19511958    pStream->u16FIFOS   = HDA_STREAM_REG(pThis, FIFOS, pStream->u8SD) + 1;
    19521959
    1953     RT_ZERO(pStream->State.BDLE);
    1954     pStream->State.uCurBDLE = 0;
    1955 
    1956     if (pStream->State.pCircBuf)
    1957         RTCircBufReset(pStream->State.pCircBuf);
    1958 
    19591960    /* Make sure to also update the stream's DMA counter (based on its current LPIB value). */
    19601961    hdaStreamUpdateLPIB(pThis, pStream, HDA_STREAM_REG(pThis, LPIB, pStream->u8SD));
     
    19621963    int rc = hdaSDFMTToStrmCfg(HDA_STREAM_REG(pThis, FMT, uSD), &pStream->State.strmCfg);
    19631964    if (RT_FAILURE(rc))
     1965    {
    19641966        LogRel(("HDA: Warning: Format 0x%x for stream #%RU8 not supported\n", HDA_STREAM_REG(pThis, FMT, uSD), uSD));
    1965 
    1966     /* Reset stream map. */
    1967     hdaStreamMapReset(&pStream->State.Mapping);
    1968 
    1969     /* (Re-)init the stream's period. */
    1970     hdaStreamPeriodInit(&pStream->State.Period, pStream->u8SD, pStream->u16LVI, pStream->u32CBL, &pStream->State.strmCfg);
     1967        return rc;
     1968    }
     1969
     1970    PPDMAUDIOSTREAMCFG pCfg = &pStream->State.strmCfg;
     1971
     1972    /* Set the stream's direction. */
     1973    pCfg->enmDir = hdaGetDirFromSD(pStream->u8SD);
     1974
     1975    /* The the stream's name, based on the direction. */
     1976    switch (pCfg->enmDir)
     1977    {
     1978        case PDMAUDIODIR_IN:
     1979# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
     1980#  error "Implement me!"
     1981# else
     1982            pCfg->DestSource.Source = PDMAUDIORECSOURCE_LINE;
     1983            RTStrCopy(pCfg->szName, sizeof(pCfg->szName), "Line In");
     1984# endif
     1985            break;
     1986
     1987        case PDMAUDIODIR_OUT:
     1988            /* Destination(s) will be set in hdaAddStreamOut(),
     1989             * based on the channels / stream layout. */
     1990            break;
     1991
     1992        default:
     1993            rc = VERR_NOT_SUPPORTED;
     1994            break;
     1995    }
     1996
     1997    /*
     1998     * Initialize the stream mapping in any case, regardless if
     1999     * we support surround audio or not. This is needed to handle
     2000     * the supported channels within a single audio stream, e.g. mono/stereo.
     2001     *
     2002     * In other words, the stream mapping *always* knows the real
     2003     * number of channels in a single audio stream.
     2004     */
     2005    rc = hdaStreamMapInit(&pStream->State.Mapping, pCfg);
     2006    AssertRCReturn(rc, rc);
    19712007
    19722008    LogFunc(("[SD%RU8] DMA @ 0x%x (%RU32 bytes), LVI=%RU16, FIFOS=%RU16, rc=%Rrc\n",
     
    20242060#endif
    20252061
     2062    RT_ZERO(pStream->State.BDLE);
     2063    pStream->State.uCurBDLE = 0;
     2064
     2065    if (pStream->State.pCircBuf)
     2066        RTCircBufReset(pStream->State.pCircBuf);
     2067
     2068    /* Reset stream map. */
     2069    hdaStreamMapReset(&pStream->State.Mapping);
     2070
    20262071    /* (Re-)initialize the stream with current values. */
    20272072    int rc2 = hdaStreamInit(pThis, pStream, uSD);
    20282073    AssertRC(rc2);
     2074
     2075    /* Reset the stream's period. */
     2076    hdaStreamPeriodReset(&pStream->State.Period);
    20292077
    20302078#ifdef DEBUG
     
    20652113    int rc = VINF_SUCCESS;
    20662114
    2067     hdaStreamLock(pStream);
    2068 
    2069 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    2070     hdaStreamAsyncIOLock(pStream);
    2071     hdaStreamAsyncIOEnable(pStream, fEnable);
    2072 #endif
    2073 
    20742115    if (pStream->pMixSink) /* Stream attached to a sink? */
    20752116    {
     
    20822123    }
    20832124
    2084     if (fEnable)
    2085     {
    2086         /* (Re-)initialize the stream with current values. */
    2087         int rc2 = hdaStreamInit(pThis, pStream, pStream->u8SD);
    2088         AssertRC(rc2);
    2089 
    2090         /* Begin a new period for this stream. */
    2091         rc2 = hdaStreamPeriodBegin(&pStream->State.Period, hdaWalClkGetCurrent(pThis)/* Use current wall clock time */);
    2092         AssertRC(rc2);
    2093     }
    2094     else
    2095     {
    2096         /* Reset the period. */
    2097         hdaStreamPeriodReset(&pStream->State.Period);
    2098     }
    2099 
    2100 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    2101     hdaStreamAsyncIOUnlock(pStream);
    2102 #endif
    2103 
    2104     /* Make sure to leave the lock before (eventually) starting the timer. */
    2105     hdaStreamUnlock(pStream);
    2106 
    2107 #ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
    2108     /* Second, see if we need to start or stop the timer. */
    2109     if (!fEnable)
    2110         hdaTimerMaybeStop(pThis);
    2111     else
    2112         hdaTimerMaybeStart(pThis);
    2113 #endif
    2114 
    2115     LogFunc(("[SD%RU8]: cStreamsActive=%RU8, rc=%Rrc\n", pStream->u8SD, pThis->cStreamsActive, rc));
     2125    LogFunc(("[SD%RU8] rc=%Rrc\n", pStream->u8SD, rc));
    21162126    return rc;
    21172127}
     
    26702680        hdaStreamLock(pStream);
    26712681
     2682#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     2683        hdaStreamAsyncIOLock(pStream);
     2684        hdaStreamAsyncIOEnable(pStream, false /* fEnable */);
     2685#endif
    26722686        hdaStreamReset(pThis, pStream, pStream->u8SD);
    26732687
     2688#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     2689        hdaStreamAsyncIOUnlock(pStream);
     2690#endif
    26742691        hdaStreamUnlock(pStream);
    26752692    }
     
    26842701            LogFunc(("[SD%RU8]: State changed (fRun=%RTbool)\n", pStream->u8SD, fRun));
    26852702
     2703            hdaStreamLock(pStream);
     2704
     2705#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     2706            hdaStreamAsyncIOLock(pStream);
     2707            hdaStreamAsyncIOEnable(pStream, fRun /* fEnable */);
     2708#endif
     2709            /* (Re-)initialize the stream with current values. */
     2710            int rc2 = hdaStreamInit(pThis, pStream, pStream->u8SD);
     2711            AssertRC(rc2);
     2712
     2713            /* Enable/disable the stream. */
    26862714            hdaStreamEnable(pThis, pStream, fRun /* fEnable */);
    26872715
    2688             if (!fRun)
     2716            if (fRun)
     2717            {
     2718                /* (Re-)init the stream's period. */
     2719                hdaStreamPeriodInit(&pStream->State.Period,
     2720                                    pStream->u8SD, pStream->u16LVI, pStream->u32CBL, &pStream->State.strmCfg);
     2721
     2722                /* Begin a new period for this stream. */
     2723                rc2 = hdaStreamPeriodBegin(&pStream->State.Period, hdaWalClkGetCurrent(pThis)/* Use current wall clock time */);
     2724                AssertRC(rc2);
     2725            }
     2726            else
    26892727            {
    26902728                /* Make sure to (re-)schedule outstanding (delayed) interrupts. */
    26912729                hdaReschedulePendingInterrupts(pThis);
     2730
     2731                /* Reset the period. */
     2732                hdaStreamPeriodReset(&pStream->State.Period);
    26922733            }
     2734
     2735#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     2736            hdaStreamAsyncIOUnlock(pStream);
     2737#endif
     2738            /* Make sure to leave the lock before (eventually) starting the timer. */
     2739            hdaStreamUnlock(pStream);
     2740
     2741#ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
     2742            /* See if we need to start or stop the timer. */
     2743            if (!fRun)
     2744                hdaTimerMaybeStop(pThis);
     2745            else
     2746                hdaTimerMaybeStart(pThis);
     2747#endif
    26932748        }
    26942749    }
     
    29863041}
    29873042
     3043/**
     3044 * Adds an audio output stream to the device setup using the given configuration.
     3045 *
     3046 * @returns IPRT status code.
     3047 * @param   pThis               Device state.
     3048 * @param   pCfg                Stream configuration to use for adding a stream.
     3049 */
    29883050static int hdaAddStreamOut(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
    29893051{
     
    31103172}
    31113173
     3174/**
     3175 * Adds an audio input stream to the device setup using the given configuration.
     3176 *
     3177 * @returns IPRT status code.
     3178 * @param   pThis               Device state.
     3179 * @param   pCfg                Stream configuration to use for adding a stream.
     3180 */
    31123181static int hdaAddStreamIn(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
    31133182{
     
    31473216    return rc;
    31483217}
     3218
     3219/**
     3220 * Adds an audio stream to the device setup using the given configuration.
     3221 *
     3222 * @returns IPRT status code.
     3223 * @param   pThis               Device state.
     3224 * @param   pCfg                Stream configuration to use for adding a stream.
     3225 */
     3226static int hdaAddStream(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
     3227{
     3228    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     3229    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
     3230
     3231    int rc = VINF_SUCCESS;
     3232
     3233    PHDADRIVER pDrv;
     3234    RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
     3235    {
     3236        int rc2;
     3237
     3238        switch (pCfg->enmDir)
     3239        {
     3240            case PDMAUDIODIR_OUT:
     3241                rc2 = hdaAddStreamOut(pThis, pCfg);
     3242                break;
     3243
     3244            case PDMAUDIODIR_IN:
     3245                rc2 = hdaAddStreamIn(pThis, pCfg);
     3246                break;
     3247
     3248            default:
     3249                rc2 = VERR_NOT_SUPPORTED;
     3250                AssertFailed();
     3251                break;
     3252        }
     3253
     3254        if (   RT_FAILURE(rc2)
     3255            && (pDrv->fFlags & PDMAUDIODRVFLAGS_PRIMARY)) /* We only care about primary drivers here, the rest may fail. */
     3256        {
     3257            if (RT_SUCCESS(rc))
     3258                rc = rc2;
     3259            /* Keep going. */
     3260        }
     3261    }
     3262
     3263    return rc;
     3264}
    31493265#endif /* IN_RING3 */
    31503266
     
    31603276    }
    31613277
    3162     PPDMAUDIOSTREAMCFG pCfg = &pStream->State.strmCfg;
    3163 
    3164     int rc = hdaSDFMTToStrmCfg(u32Value, pCfg);
    3165     if (RT_FAILURE(rc))
    3166         return VINF_SUCCESS; /* Always return success to the MMIO handler. */
    3167 
    3168     LogFunc(("[SD%RU8]: Hz=%RU32, Channels=%RU8, cBits=%RU8\n",
    3169              pStream->u8SD, pCfg->Props.uHz, pCfg->Props.cChannels, pCfg->Props.cBits));
    3170 
    3171     /* Set audio direction. */
    3172     pCfg->enmDir = hdaGetDirFromSD(pStream->u8SD);
    3173     switch (pCfg->enmDir)
    3174     {
    3175         case PDMAUDIODIR_IN:
    3176 # ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
    3177 #  error "Implement me!"
    3178 # else
    3179             pCfg->DestSource.Source = PDMAUDIORECSOURCE_LINE;
    3180             RTStrCopy(pCfg->szName, sizeof(pCfg->szName), "Line In");
    3181 # endif
    3182             break;
    3183 
    3184         case PDMAUDIODIR_OUT:
    3185             /* Destination(s) will be set in hdaAddStreamOut(),
    3186              * based on the channels / stream layout. */
    3187             break;
    3188 
    3189         default:
    3190             rc = VERR_NOT_SUPPORTED;
    3191             break;
    3192     }
    3193 
     3278    int rc = hdaRegWriteU16(pThis, iReg, u32Value);
     3279    AssertRC(rc);
     3280
     3281    rc = hdaStreamInit(pThis, pStream, pStream->u8SD);
     3282    if (RT_SUCCESS(rc))
     3283    {
     3284        /* Add the stream to the device setup. */
     3285        rc = hdaAddStream(pThis, &pStream->State.strmCfg);
    31943286#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    3195     if (RT_SUCCESS(rc))
    3196     {
    3197         rc = hdaStreamAsyncIOCreate(pThis, pStream);
    3198         AssertRC(rc);
    3199     }
    3200 #endif
    3201 
    3202     /*
    3203      * Initialize the stream mapping in any case, regardless if
    3204      * we support surround audio or not. This is needed to handle
    3205      * the supported channels within a single audio stream, e.g. mono/stereo.
    3206      *
    3207      * In other words, the stream mapping *always* knows the real
    3208      * number of channels in a single audio stream.
    3209      */
    3210     if (RT_SUCCESS(rc))
    3211     {
    3212         rc = hdaStreamMapInit(&pStream->State.Mapping, pCfg);
    3213         AssertRC(rc);
    3214     }
    3215 
    3216     if (RT_SUCCESS(rc))
    3217     {
    3218         PHDADRIVER pDrv;
    3219         RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
    3220         {
    3221             int rc2;
    3222             switch (pCfg->enmDir)
    3223             {
    3224                 case PDMAUDIODIR_OUT:
    3225                     rc2 = hdaAddStreamOut(pThis, pCfg);
    3226                     break;
    3227 
    3228                 case PDMAUDIODIR_IN:
    3229                     rc2 = hdaAddStreamIn(pThis, pCfg);
    3230                     break;
    3231 
    3232                 default:
    3233                     rc2 = VERR_NOT_SUPPORTED;
    3234                     AssertFailed();
    3235                     break;
    3236             }
    3237 
    3238             if (   RT_FAILURE(rc2)
    3239                 && (pDrv->fFlags & PDMAUDIODRVFLAGS_PRIMARY)) /* We only care about primary drivers here, the rest may fail. */
    3240             {
    3241                 if (RT_SUCCESS(rc))
    3242                     rc = rc2;
    3243                 /* Keep going. */
    3244             }
    3245         }
    3246 
    3247         /* If (re-)opening the stream by the codec above failed, don't write the new
    3248          * format to the register so that the guest is aware it didn't work. */
    32493287        if (RT_SUCCESS(rc))
    3250         {
    3251             rc = hdaRegWriteU16(pThis, iReg, u32Value);
    3252             AssertRC(rc);
    3253         }
    3254         else
    3255             LogFunc(("[SD%RU8]: (Re-)Opening stream failed with rc=%Rrc\n", pStream->u8SD, rc));
    3256     }
    3257 
     3288            rc = hdaStreamAsyncIOCreate(pThis, pStream);
     3289    }
     3290#endif
    32583291    return VINF_SUCCESS; /* Never return failure. */
    32593292#else /* !IN_RING3 */
     
    59495982    AssertRCReturn(rc, rc);
    59505983
     5984    rc = SSMR3PutStructEx(pSSM, &pStrm->State.Period, sizeof(HDASTREAMPERIOD),
     5985                          0 /* fFlags */, g_aSSMStreamPeriodFields7, NULL);
     5986    AssertRCReturn(rc, rc);
     5987
    59515988#ifdef VBOX_STRICT /* Sanity checks. */
    59525989    PHDABDLE pBDLE = &pStrm->State.BDLE;
     
    60526089    SSMR3PutMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
    60536090
    6054     /* Save the controller's base timestamp (for handling the WALCLK register).
    6055      * This is needed to continue with correct time keeping on VM resume. */
    6056     SSMR3PutU64(pSSM, pThis->u64BaseTS);
     6091    /* Load controller-specifc internals. */
     6092    SSMR3PutU64(pSSM, pThis->u64WalClk);
     6093    SSMR3PutU8(pSSM, pThis->u8IRQL);
    60576094
    60586095    /* Save number of streams. */
     
    60886125        if (pStream)
    60896126        {
    6090             hdaStreamEnable(pThis, pStream, false /* fEnable */);
     6127            int rc2;
    60916128
    60926129            bool fActive = RT_BOOL(HDA_STREAM_REG(pThis, CTL, i) & HDA_SDCTL_RUN);
    60936130            if (fActive)
    60946131            {
    6095                 int rc2;
    6096 
    60976132#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    60986133                /* Make sure to also create the async I/O thread before actually enabling the stream. */
    60996134                rc2 = hdaStreamAsyncIOCreate(pThis, pStream);
    61006135                AssertRC(rc2);
    6101 #endif
     6136
     6137                /* ... and enabling it. */
     6138                hdaStreamAsyncIOEnable(pStream, true /* fEnable */);
     6139#endif
     6140                /* (Re-)initialize the stream with current values. */
     6141                rc2 = hdaStreamInit(pThis, pStream, pStream->u8SD);
     6142                AssertRC(rc2);
     6143
     6144                /* Resume the stream's period. */
     6145                hdaStreamPeriodResume(&pStream->State.Period);
     6146
     6147                /* (Re-)enable the stream. */
    61026148                rc2 = hdaStreamEnable(pThis, pStream, true /* fEnable */);
    61036149                AssertRC(rc2);
    61046150
     6151                /* Add the stream to the device setup. */
     6152                rc2 = hdaAddStream(pThis, &pStream->State.strmCfg);
     6153                AssertRC(rc2);
     6154
    61056155#ifdef HDA_USE_DMA_ACCESS_HANDLER
     6156                /* (Re-)install the DMA handler. */
    61066157                hdaStreamRegisterDMAHandlers(pThis, pStream);
    61076158#endif
     
    61126163
    61136164#ifndef VBOX_WITH_AUDIO_CALLBACKS
    6114     if (   fStartTimer
    6115         && pThis->pTimer
    6116         && !TMTimerIsActive(pThis->pTimer))
    6117     {
    6118         pThis->tsTimerExpire = TMTimerGet(pThis->pTimer) + pThis->cTimerTicks;
    6119 
    6120         /* Resume timer. */
    6121         int rc2 = TMTimerSet(pThis->pTimer, pThis->tsTimerExpire);
    6122         AssertRC(rc2);
    6123     }
     6165    /* Start the timer if one of the above streams were active during taking the saved state. */
     6166    if (fStartTimer)
     6167        hdaTimerMaybeStart(pThis);
    61246168#endif
    61256169
     
    64706514     * Load controller-specifc internals.
    64716515     */
    6472     rc = SSMR3GetU64(pSSM, &pThis->u64BaseTS);
    6473     AssertRC(rc);
     6516    if (SSMR3HandleRevision(pSSM) >= 116273) /* Don't annoy other team mates (forgot this for state v7). */
     6517    {
     6518        rc = SSMR3GetU64(pSSM, &pThis->u64WalClk);
     6519        AssertRC(rc);
     6520
     6521        rc = SSMR3GetU8(pSSM, &pThis->u8IRQL);
     6522        AssertRC(rc);
     6523    }
    64746524
    64756525    /*
     
    65226572
    65236573        Log2Func(("[SD%RU8] %R[bdle]\n", pStrm->u8SD, &pStrm->State.BDLE));
     6574
     6575        /*
     6576         * Load period state.
     6577         */
     6578        hdaStreamPeriodInit(&pStrm->State.Period,
     6579                            pStrm->u8SD, pStrm->u16LVI, pStrm->u32CBL, &pStrm->State.strmCfg);
     6580
     6581        if (SSMR3HandleRevision(pSSM) >= 116273) /* Don't annoy other team mates (forgot this for state v7). */
     6582        {
     6583            rc = SSMR3GetStructEx(pSSM, &pStrm->State.Period, sizeof(HDASTREAMPERIOD),
     6584                                  0 /* fFlags */, g_aSSMStreamPeriodFields7, NULL);
     6585            AssertRC(rc);
     6586        }
    65246587
    65256588        /*
     
    69767039    else
    69777040        pThis->pu64RirbBuf = (uint64_t *)RTMemAllocZ(pThis->cbRirbBuf);
    6978 
    6979     pThis->u64BaseTS = PDMDevHlpTMTimeVirtGetNano(pDevIns);
    69807041
    69817042    for (uint8_t uSD = 0; uSD < HDA_MAX_STREAMS; ++uSD)
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp

    r67410 r67533  
    18991899    GEN_CHECK_OFF(HDASTATE, SinkMicIn);
    19001900#endif
    1901     GEN_CHECK_OFF(HDASTATE, u64BaseTS);
     1901    GEN_CHECK_OFF(HDASTATE, u64WalClk);
    19021902    GEN_CHECK_OFF(HDASTATE, u8RespIntCnt);
     1903    GEN_CHECK_OFF(HDASTATE, u8IRQL);
    19031904
    19041905#ifdef VBOX_WITH_NVME_IMPL
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

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