VirtualBox

Changeset 55009 in vbox for trunk/src


Ignore:
Timestamp:
Mar 30, 2015 3:33:15 PM (10 years ago)
Author:
vboxsync
Message:

PDM/DevSB16.cpp: Implemented LUN handling, minor cleanups + formatting.

File:
1 edited

Legend:

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

    r55005 r55009  
    33 * DevSB16 - VBox SB16 Audio Controller.
    44 *
    5  * (r3917 sb16.c)
    6  *
    75 * @todo hiccups on NT4 and Win98.
    86 */
    97
    108/*
     9 * Copyright (C) 2015 Oracle Corporation
     10 *
     11 * This file is part of VirtualBox Open Source Edition (OSE), as
     12 * available from http://www.virtualbox.org. This file is free software;
     13 * you can redistribute it and/or modify it under the terms of the GNU
     14 * General Public License (GPL) as published by the Free Software
     15 * Foundation, in version 2 as it comes in the "COPYING" file of the
     16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
     17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
     18 * --------------------------------------------------------------------
     19 *
     20 * This code is based on: sb16.c from QEMU AUDIO subsystem (r3917).
    1121 * QEMU Soundblaster 16 emulation
    1222 *
     
    3242 */
    3343
    34 #define LOG_GROUP LOG_GROUP_DEV_AUDIO
     44#include <iprt/assert.h>
     45#ifdef IN_RING3
     46# include <iprt/mem.h>
     47# include <iprt/string.h>
     48# include <iprt/uuid.h>
     49#endif
     50
    3551#include <VBox/vmm/pdmdev.h>
    3652#include <VBox/vmm/pdmaudioifs.h>
    37 #include <iprt/assert.h>
    38 #include <iprt/string.h>
    39 #include <iprt/uuid.h>
     53
    4054#include "vl_vbox.h"
     55
     56#ifdef LOG_GROUP
     57 #undef LOG_GROUP
     58#endif
     59#define LOG_GROUP LOG_GROUP_DEV_AUDIO
     60#include <VBox/log.h>
    4161
    4262#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     
    169189    int use_hdma;
    170190    int highspeed;
    171     int can_write;
     191    int can_write; /** @Todo Value never gets 0? */
    172192
    173193    int v2x6;
     
    196216
    197217#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    198     R3PTRTYPE(PPDMAUDIOGSTSTRMOUT) pGstStrmOut;
    199     /** List of associated LUN drivers. */
    200218    RTLISTANCHOR                   lstDrv;
    201219    /** The device' software mixer. */
     
    203221    /** Audio sink for PCM output. */
    204222    R3PTRTYPE(PAUDMIXSINK)         pSinkOutput;
     223    /** The emulation timer for handling I/O of the attached LUN drivers. */
     224    PTMTIMERR3                     pTimerIO;
     225    /** Timer ticks for handling the LUN drivers. */
     226    uint64_t                       uTicksIO;
    205227#else
    206228    SWVoiceOut *voice;
    207229#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    208230
    209     PTMTIMER  pTimer;
     231    PTMTIMER  pTimerIRQ;
    210232    PPDMIBASE pDrvBase;
    211233    /** LUN\#0: Base interface. */
     
    218240
    219241#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     242static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg);
     243#endif
     244
     245#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     246/**
     247 * Attach command.
     248 *
     249 * This is called to let the device attach to a driver for a specified LUN
     250 * during runtime. This is not called during VM construction, the device
     251 * constructor have to attach to all the available drivers.
     252 *
     253 * @returns VBox status code.
     254 * @param   pDevIns     The device instance.
     255 * @param   uLUN        The logical unit which is being detached.
     256 * @param   fFlags      Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
     257 */
     258static DECLCALLBACK(int) sb16Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
     259{
     260    PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
     261
     262    AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
     263                    ("AC'97 device does not support hotplugging\n"),
     264                    VERR_INVALID_PARAMETER);
     265
     266    /*
     267     * Attach driver.
     268     */
     269    char *pszDesc = NULL;
     270    if (RTStrAPrintf(&pszDesc, "Audio driver port (SB16) for LUN #%u", uLUN) <= 0)
     271        AssertMsgReturn(pszDesc,
     272                        ("Not enough memory for SB16 driver port description of LUN #%u\n", uLUN),
     273                        VERR_NO_MEMORY);
     274
     275    int rc = PDMDevHlpDriverAttach(pDevIns, uLUN,
     276                                   &pThis->IBase, &pThis->pDrvBase, pszDesc);
     277    if (RT_SUCCESS(rc))
     278    {
     279        PSB16DRIVER pDrv = (PSB16DRIVER)RTMemAllocZ(sizeof(SB16DRIVER));
     280        if (pDrv)
     281        {
     282            pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIAUDIOCONNECTOR);
     283            AssertMsg(pDrv->pConnector != NULL,
     284                      ("Configuration error: LUN #%u has no host audio interface, rc=%Rrc\n",
     285                      uLUN, rc));
     286            pDrv->pSB16State = pThis;
     287            pDrv->uLUN = uLUN;
     288
     289            /*
     290             * For now we always set the driver at LUN 0 as our primary
     291             * host backend. This might change in the future.
     292             */
     293            if (pDrv->uLUN == 0)
     294                pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
     295
     296            LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
     297
     298            /* Attach to driver list. */
     299            RTListAppend(&pThis->lstDrv, &pDrv->Node);
     300        }
     301        else
     302            rc = VERR_NO_MEMORY;
     303    }
     304    else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
     305    {
     306        LogFunc(("No attached driver for LUN #%u\n", uLUN));
     307    }
     308    else if (RT_FAILURE(rc))
     309        AssertMsgFailed(("Failed to attach SB16 LUN #%u (\"%s\"), rc=%Rrc\n",
     310                        uLUN, pszDesc, rc));
     311
     312    RTStrFree(pszDesc);
     313
     314    LogFunc(("iLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
     315    return rc;
     316}
     317#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
     318
     319#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    220320static void sb16AudioCallback(void *pvContext, uint32_t cbFree);
    221321#else
     
    225325static int magic_of_irq (int irq)
    226326{
    227     switch (irq) {
    228     case 5:
    229         return 2;
    230     case 7:
    231         return 4;
    232     case 9:
    233         return 1;
    234     case 10:
    235         return 8;
    236     default:
    237         LogFlowFunc(("bad irq %d\n", irq));
    238         return 2;
    239     }
     327    switch (irq)
     328    {
     329        case 5:
     330            return 2;
     331        case 7:
     332            return 4;
     333        case 9:
     334            return 1;
     335        case 10:
     336            return 8;
     337        default:
     338            break;
     339    }
     340
     341    LogFlowFunc(("bad irq %d\n", irq));
     342    return 2;
    240343}
    241344
    242345static int irq_of_magic (int magic)
    243346{
    244     switch (magic) {
    245     case 1:
    246         return 9;
    247     case 2:
    248         return 5;
    249     case 4:
    250         return 7;
    251     case 8:
    252         return 10;
    253     default:
    254         LogFlowFunc(("bad irq magic %d\n", magic));
    255         return -1;
    256     }
     347    switch (magic)
     348    {
     349        case 1:
     350            return 9;
     351        case 2:
     352            return 5;
     353        case 4:
     354            return 7;
     355        case 8:
     356            return 10;
     357        default:
     358            break;
     359    }
     360
     361    LogFlowFunc(("bad irq magic %d\n", magic));
     362    return -1;
    257363}
    258364
    259365#if 0
    260 static void log_dsp (SB16State *dsp)
     366static void log_dsp (PSB16STATE dsp)
    261367{
    262368    ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
     
    272378#endif
    273379
    274 static void speaker (PSB16STATE pThis, int on)
     380static void sb16SpeakerControl(PSB16STATE pThis, int on)
    275381{
    276382    pThis->speaker = on;
     
    278384}
    279385
    280 static void control (PSB16STATE pThis, int hold)
     386static void sb16Control(PSB16STATE pThis, int hold)
    281387{
    282388    int dma = pThis->use_hdma ? pThis->hdma : pThis->dma;
     
    295401    }
    296402#else  /* VBOX */
     403# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     404    PSB16DRIVER pDrv;
     405# endif
    297406    if (hold)
    298407    {
    299408        PDMDevHlpDMASetDREQ (pThis->pDevIns, dma, 1);
    300409        PDMDevHlpDMASchedule (pThis->pDevIns);
    301 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    302         pThis->pDrv->pfnEnableOut(pThis->pDrv, pThis->pGstStrmOut, true /* fEnable */);
    303 #else
     410# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     411        RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     412            pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
     413                                           pDrv->Out.pStrmOut, true /* fEnable */);
     414# else
    304415        AUD_set_active_out (pThis->voice, 1);
    305 #endif
     416# endif
    306417    }
    307418    else
    308419    {
    309420        PDMDevHlpDMASetDREQ (pThis->pDevIns, dma, 0);
    310 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    311         pThis->pDrv->pfnEnableOut(pThis->pDrv, pThis->pGstStrmOut, false /* fEnable */);
    312 #else
     421# ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     422        RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     423            pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
     424                                           pDrv->Out.pStrmOut, false /* fEnable */);
     425# else
    313426        AUD_set_active_out (pThis->voice, 0);
    314 #endif
     427# endif
    315428    }
    316429#endif /* VBOX */
     
    325438}
    326439#else  /* VBOX */
    327 static DECLCALLBACK(void) sb16Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvThis)
    328 {
    329     PSB16STATE pThis = (SB16STATE *)pvThis;
     440static DECLCALLBACK(void) sb16TimerIRQ(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvThis)
     441{
     442    PSB16STATE pThis = (PSB16STATE)pvThis;
    330443    pThis->can_write = 1;
    331444    PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
     
    336449#define DMA8_HIGH 2
    337450
    338 static void continue_dma8 (PSB16STATE pThis)
     451static void continue_dma8(PSB16STATE pThis)
    339452{
    340453    if (pThis->freq > 0)
     
    343456
    344457#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    345         PDMAUDIOSTREAMCFG as;
    346         as.uHz           = pThis->freq;
    347         as.cChannels     = 1 << pThis->fmt_stereo;
    348         as.enmFormat     = pThis->fmt;
    349         as.enmEndianness = PDMAUDIOHOSTENDIANESS;
    350 
    351         int rc = pThis->pDrv->pfnOpenOut(pThis->pDrv, "sb16.out", &as, &pThis->pGstStrmOut);
     458        PDMAUDIOSTREAMCFG streamCfg;
     459        streamCfg.uHz           = pThis->freq;
     460        streamCfg.cChannels     = 1 << pThis->fmt_stereo;
     461        streamCfg.enmFormat     = pThis->fmt;
     462        streamCfg.enmEndianness = PDMAUDIOHOSTENDIANESS;
     463
     464        int rc = sb16OpenOut(pThis, &streamCfg);
    352465        AssertRC(rc);
    353466#else
    354         audsettings_t as;
    355         as.freq = pThis->freq;
    356         as.nchannels = 1 << pThis->fmt_stereo;
    357         as.fmt = pThis->fmt;
    358         as.endianness = 0;
     467        audsettings_t streamCfg;
     468        streamCfg.freq = pThis->freq;
     469        streamCfg.nchannels = 1 << pThis->fmt_stereo;
     470        streamCfg.fmt = pThis->fmt;
     471        streamCfg.endianness = 0;
    359472        pThis->voice = AUD_open_out (
    360473            &pThis->card,
     
    363476            pThis,
    364477            sb16AudioCallback,
    365             &as
     478            &streamCfg
    366479            );
    367480#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    368481    }
    369482
    370     control(pThis, 1);
    371 }
    372 
    373 static void dma_cmd8 (PSB16STATE pThis, int mask, int dma_len)
    374 {
    375     pThis->fmt = AUD_FMT_U8;
    376     pThis->use_hdma = 0;
    377     pThis->fmt_bits = 8;
     483    sb16Control(pThis, 1);
     484}
     485
     486static void dma_cmd8(PSB16STATE pThis, int mask, int dma_len)
     487{
     488    pThis->fmt        = AUD_FMT_U8;
     489    pThis->use_hdma   = 0;
     490    pThis->fmt_bits   = 8;
    378491    pThis->fmt_signed = 0;
    379492    pThis->fmt_stereo = (pThis->mixer_regs[0x0e] & 2) != 0;
    380     if (-1 == pThis->time_const) {
     493
     494    if (-1 == pThis->time_const)
     495    {
    381496        if (pThis->freq <= 0)
    382497            pThis->freq = 11025;
    383498    }
    384     else {
     499    else
     500    {
    385501        int tmp = (256 - pThis->time_const);
    386502        pThis->freq = (1000000 + (tmp / 2)) / tmp;
    387503    }
    388504
    389     if (dma_len != -1) {
     505    if (dma_len != -1)
     506    {
    390507        pThis->block_size = dma_len << pThis->fmt_stereo;
    391508    }
    392     else {
     509    else
     510    {
    393511        /* This is apparently the only way to make both Act1/PL
    394512           and SecondReality/FC work
     
    421539
    422540    continue_dma8 (pThis);
    423     speaker (pThis, 1);
     541    sb16SpeakerControl(pThis, 1);
    424542}
    425543
    426544static void dma_cmd (PSB16STATE pThis, uint8_t cmd, uint8_t d0, int dma_len)
    427545{
    428     pThis->use_hdma = cmd < 0xc0;
    429     pThis->fifo = (cmd >> 1) & 1;
    430     pThis->dma_auto = (cmd >> 2) & 1;
     546    pThis->use_hdma   = cmd < 0xc0;
     547    pThis->fifo       = (cmd >> 1) & 1;
     548    pThis->dma_auto   = (cmd >> 2) & 1;
    431549    pThis->fmt_signed = (d0 >> 4) & 1;
    432550    pThis->fmt_stereo = (d0 >> 5) & 1;
    433551
    434     switch (cmd >> 4) {
    435     case 11:
    436         pThis->fmt_bits = 16;
    437         break;
    438 
    439     case 12:
    440         pThis->fmt_bits = 8;
    441         break;
    442     }
    443 
    444     if (-1 != pThis->time_const) {
     552    switch (cmd >> 4)
     553    {
     554        case 11:
     555            pThis->fmt_bits = 16;
     556            break;
     557
     558        case 12:
     559            pThis->fmt_bits = 8;
     560            break;
     561    }
     562
     563    if (-1 != pThis->time_const)
     564    {
    445565#if 1
    446566        int tmp = 256 - pThis->time_const;
     
    455575    pThis->block_size = dma_len + 1;
    456576    pThis->block_size <<= ((pThis->fmt_bits == 16) ? 1 : 0);
    457     if (!pThis->dma_auto) {
     577    if (!pThis->dma_auto)
     578    {
    458579        /* It is clear that for DOOM and auto-init this value
    459580           shouldn't take stereo into account, while Miles Sound Systems
     
    463584    }
    464585
    465     LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, "
    466             "dma %d, auto %d, fifo %d, high %d\n",
    467             pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
    468             pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
    469 
    470     if (16 == pThis->fmt_bits) {
    471         if (pThis->fmt_signed) {
    472             pThis->fmt = AUD_FMT_S16;
    473         }
    474         else {
    475             pThis->fmt = AUD_FMT_U16;
    476         }
    477     }
    478     else {
    479         if (pThis->fmt_signed) {
    480             pThis->fmt = AUD_FMT_S8;
    481         }
    482         else {
    483             pThis->fmt = AUD_FMT_U8;
    484         }
    485     }
     586    LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, dma %d, auto %d, fifo %d, high %d\n",
     587                 pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
     588                 pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
     589
     590    if (16 == pThis->fmt_bits)
     591        pThis->fmt = pThis->fmt_signed ? AUD_FMT_S16 : AUD_FMT_U16;
     592    else
     593        pThis->fmt = pThis->fmt_signed ? AUD_FMT_S8 : AUD_FMT_U8;
    486594
    487595    pThis->left_till_irq = pThis->block_size;
     
    490598    pThis->highspeed = 0;
    491599    pThis->align = (1 << (pThis->fmt_stereo + (pThis->fmt_bits == 16))) - 1;
    492     if (pThis->block_size & pThis->align) {
     600    if (pThis->block_size & pThis->align)
     601    {
    493602        LogFlowFunc(("warning: misaligned block size %d, alignment %d\n",
    494                pThis->block_size, pThis->align + 1));
     603                     pThis->block_size, pThis->align + 1));
    495604    }
    496605
     
    500609
    501610#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    502         PDMAUDIOSTREAMCFG as;
    503         as.uHz           = pThis->freq;
    504         as.cChannels     = 1 << pThis->fmt_stereo;
    505         as.enmFormat     = pThis->fmt;
    506         as.enmEndianness = PDMAUDIOHOSTENDIANESS;
    507 
    508         int rc = pThis->pDrv->pfnOpenOut(pThis->pDrv, "sb16.out", &as, &pThis->pGstStrmOut);
     611        PDMAUDIOSTREAMCFG streamCfg;
     612        streamCfg.uHz           = pThis->freq;
     613        streamCfg.cChannels     = 1 << pThis->fmt_stereo;
     614        streamCfg.enmFormat     = pThis->fmt;
     615        streamCfg.enmEndianness = PDMAUDIOHOSTENDIANESS;
     616
     617        int rc = sb16OpenOut(pThis, &streamCfg);
    509618        AssertRC(rc);
    510619#else
    511         audsettings_t as;
    512         as.freq = pThis->freq;
    513         as.nchannels = 1 << pThis->fmt_stereo;
    514         as.fmt = pThis->fmt;
    515         as.endianness = 0;
     620        audsettings_t streamCfg;
     621        streamCfg.freq = pThis->freq;
     622        streamCfg.nchannels = 1 << pThis->fmt_stereo;
     623        streamCfg.fmt = pThis->fmt;
     624        streamCfg.endianness = 0;
    516625        pThis->voice = AUD_open_out (
    517626            &pThis->card,
     
    520629            pThis,
    521630            sb16AudioCallback,
    522             &as
     631            &streamCfg
    523632            );
    524633#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    525634    }
    526635
    527     control (pThis, 1);
    528     speaker (pThis, 1);
     636    sb16Control(pThis, 1);
     637    sb16SpeakerControl(pThis, 1);
    529638}
    530639
     
    684793        case 0x90:
    685794        case 0x91:
    686             dma_cmd8 (pThis, (((cmd & 1) == 0) ? 1 : 0) | DMA8_HIGH, -1);
     795            dma_cmd8(pThis, (((cmd & 1) == 0) ? 1 : 0) | DMA8_HIGH, -1);
    687796            break;
    688797
    689798        case 0xd0:              /* halt DMA operation. 8bit */
    690             control (pThis, 0);
     799            sb16Control(pThis, 0);
    691800            break;
    692801
    693802        case 0xd1:              /* speaker on */
    694             speaker (pThis, 1);
     803            sb16SpeakerControl(pThis, 1);
    695804            break;
    696805
    697806        case 0xd3:              /* speaker off */
    698             speaker (pThis, 0);
     807            sb16SpeakerControl(pThis, 0);
    699808            break;
    700809
     
    706815
    707816        case 0xd5:              /* halt DMA operation. 16bit */
    708             control (pThis, 0);
     817            sb16Control(pThis, 0);
    709818            break;
    710819
    711820        case 0xd6:              /* continue DMA operation. 16bit */
    712             control (pThis, 1);
     821            sb16Control(pThis, 1);
    713822            break;
    714823
     
    8911000
    8921001        case 0x14:
    893             dma_cmd8 (pThis, 0, dsp_get_lohi (pThis) + 1);
     1002            dma_cmd8(pThis, 0, dsp_get_lohi (pThis) + 1);
    8941003            break;
    8951004
     
    9431052                LogFlowFunc(("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks));
    9441053#else  /* VBOX */
    945                 ticks = (bytes * TMTimerGetFreq(pThis->pTimer)) / freq;
    946                 if (ticks < TMTimerGetFreq(pThis->pTimer) / 1024)
     1054                ticks = (bytes * TMTimerGetFreq(pThis->pTimerIRQ)) / freq;
     1055                if (ticks < TMTimerGetFreq(pThis->pTimerIRQ) / 1024)
    9471056                    PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
    9481057                else
    949                     TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + ticks);
     1058                    TMTimerSet(pThis->pTimerIRQ, TMTimerGet(pThis->pTimerIRQ) + ticks);
    9501059                LogFlowFunc(("mix silence %d %d % %RU64\n", samples, bytes, ticks));
    9511060#endif /* VBOX */
     
    10021111}
    10031112
    1004 static void legacy_reset (PSB16STATE pThis)
    1005 {
    1006     pThis->freq = 11025;
     1113static void legacy_reset(PSB16STATE pThis)
     1114{
     1115    pThis->freq       = 11025;
    10071116    pThis->fmt_signed = 0;
    1008     pThis->fmt_bits = 8;
     1117    pThis->fmt_bits   = 8;
    10091118    pThis->fmt_stereo = 0;
    10101119
    10111120#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1012     PDMAUDIOSTREAMCFG as;
    1013     as.uHz           = pThis->freq;
    1014     as.cChannels     = 1;
    1015     as.enmFormat     = AUD_FMT_U8;
    1016     as.enmEndianness = PDMAUDIOHOSTENDIANESS;
    1017 
    1018     int rc = pThis->pDrv->pfnOpenOut(pThis->pDrv, "sb16.out", &as, &pThis->pGstStrmOut);
     1121    PDMAUDIOSTREAMCFG streamCfg;
     1122    streamCfg.uHz           = pThis->freq;
     1123    streamCfg.cChannels     = 1; /* Mono */
     1124    streamCfg.enmFormat     = AUD_FMT_U8;
     1125    streamCfg.enmEndianness = PDMAUDIOHOSTENDIANESS;
     1126
     1127    int rc = sb16OpenOut(pThis, &streamCfg);
    10191128    AssertRC(rc);
    10201129#else
    1021     audsettings_t as;
    1022     as.freq = pThis->freq;
    1023     as.nchannels = 1;
    1024     as.fmt = AUD_FMT_U8;
    1025     as.endianness = 0;
     1130    audsettings_t streamCfg;
     1131    streamCfg.freq = pThis->freq;
     1132    streamCfg.nchannels = 1;
     1133    streamCfg.fmt = AUD_FMT_U8;
     1134    streamCfg.endianness = 0;
    10261135    pThis->voice = AUD_open_out (
    10271136        &pThis->card,
     
    10301139        pThis,
    10311140        sb16AudioCallback,
    1032         &as
     1141        &streamCfg
    10331142        );
    10341143#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
     
    10671176
    10681177    dsp_out_data(pThis, 0xaa);
    1069     speaker (pThis, 0);
    1070     control (pThis, 0);
     1178    sb16SpeakerControl(pThis, 0);
     1179    sb16Control(pThis, 0);
    10711180    legacy_reset (pThis);
    10721181}
     
    10901199                    PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
    10911200#endif
    1092                     control (pThis, 0);
     1201                    sb16Control(pThis, 0);
    10931202                }
    10941203                else {
     
    11741283#endif
    11751284
    1176     switch (iport) {
    1177     case 0x06:                  /* reset */
    1178         retval = 0xff;
    1179         break;
    1180 
    1181     case 0x0a:                  /* read data */
    1182         if (pThis->out_data_len) {
    1183             retval = pThis->out_data[--pThis->out_data_len];
    1184             pThis->last_read_byte = retval;
    1185         }
    1186         else {
    1187             if (pThis->cmd != -1) {
    1188                 LogFlowFunc(("empty output buffer for command %#x\n",
    1189                        pThis->cmd));
     1285    switch (iport)
     1286    {
     1287        case 0x06:                  /* reset */
     1288            retval = 0xff;
     1289            break;
     1290
     1291        case 0x0a:                  /* read data */
     1292            if (pThis->out_data_len)
     1293            {
     1294                retval = pThis->out_data[--pThis->out_data_len];
     1295                pThis->last_read_byte = retval;
    11901296            }
    1191             retval = pThis->last_read_byte;
    1192             /* goto error; */
    1193         }
    1194         break;
    1195 
    1196     case 0x0c:                  /* 0 can write */
    1197         retval = pThis->can_write ? 0 : 0x80;
    1198         break;
    1199 
    1200     case 0x0d:                  /* timer interrupt clear */
    1201         /* LogFlowFunc(("timer interrupt clear\n")); */
    1202         retval = 0;
    1203         break;
    1204 
    1205     case 0x0e:                  /* data available status | irq 8 ack */
    1206         retval = (!pThis->out_data_len || pThis->highspeed) ? 0 : 0x80;
    1207         if (pThis->mixer_regs[0x82] & 1) {
    1208             ack = 1;
    1209             pThis->mixer_regs[0x82] &= ~1;
     1297            else
     1298            {
     1299                if (pThis->cmd != -1)
     1300                    LogFlowFunc(("empty output buffer for command %#x\n", pThis->cmd));
     1301                retval = pThis->last_read_byte;
     1302                /* goto error; */
     1303            }
     1304            break;
     1305
     1306        case 0x0c:                  /* 0 can write */
     1307            retval = pThis->can_write ? 0 : 0x80;
     1308            break;
     1309
     1310        case 0x0d:                  /* timer interrupt clear */
     1311            /* LogFlowFunc(("timer interrupt clear\n")); */
     1312            retval = 0;
     1313            break;
     1314
     1315        case 0x0e:                  /* data available status | irq 8 ack */
     1316            retval = (!pThis->out_data_len || pThis->highspeed) ? 0 : 0x80;
     1317            if (pThis->mixer_regs[0x82] & 1)
     1318            {
     1319                ack = 1;
     1320                pThis->mixer_regs[0x82] &= ~1;
    12101321#ifndef VBOX
    1211             qemu_irq_lower (pThis->pic[pThis->irq]);
    1212 #else
    1213             PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
    1214 #endif
    1215         }
    1216         break;
    1217 
    1218     case 0x0f:                  /* irq 16 ack */
    1219         retval = 0xff;
    1220         if (pThis->mixer_regs[0x82] & 2) {
    1221             ack = 1;
    1222             pThis->mixer_regs[0x82] &= ~2;
     1322                qemu_irq_lower (pThis->pic[pThis->irq]);
     1323#else
     1324                PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
     1325#endif
     1326            }
     1327            break;
     1328
     1329        case 0x0f:                  /* irq 16 ack */
     1330            retval = 0xff;
     1331            if (pThis->mixer_regs[0x82] & 2)
     1332            {
     1333                ack = 1;
     1334                pThis->mixer_regs[0x82] &= ~2;
    12231335#ifndef VBOX
    1224             qemu_irq_lower (pThis->pic[pThis->irq]);
    1225 #else
    1226             PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
    1227 #endif
    1228         }
    1229         break;
    1230 
    1231     default:
    1232         goto error;
    1233     }
    1234 
    1235     if (!ack) {
     1336               qemu_irq_lower (pThis->pic[pThis->irq]);
     1337#else
     1338               PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
     1339#endif
     1340            }
     1341            break;
     1342
     1343        default:
     1344            goto error;
     1345    }
     1346
     1347    if (!ack)
    12361348        LogFlowFunc(("read %#x -> %#x\n", nport, retval));
    1237     }
    12381349
    12391350#ifndef VBOX
     
    12531364}
    12541365
    1255 static void reset_mixer (PSB16STATE pThis)
    1256 {
    1257     int i;
     1366static void sb16MixerReset(PSB16STATE pThis)
     1367{
     1368#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     1369    PSB16DRIVER pDrv;
     1370
     1371    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     1372        pDrv->Out.phStrmOut   = NULL;
     1373
     1374    pThis->pSinkOutput = NULL;
     1375
     1376    if (pThis->pMixer)
     1377    {
     1378        audioMixerDestroy(pThis->pMixer);
     1379        pThis->pMixer = NULL;
     1380    }
     1381#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    12581382
    12591383    memset (pThis->mixer_regs, 0xff, 0x7f);
     
    12781402    pThis->mixer_regs[0x26] = (4 << 5) | (4 << 1);
    12791403
    1280     for (i = 0x30; i < 0x48; i++) {
     1404    for (int i = 0x30; i < 0x48; i++)
    12811405        pThis->mixer_regs[i] = 0x20;
    1282     }
     1406
     1407#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     1408    int rc2 = audioMixerCreate("SB16 Mixer", 0 /* uFlags */, &pThis->pMixer);
     1409    if (RT_SUCCESS(rc2))
     1410    {
     1411        /* Set a default audio format for our mixer. */
     1412        PDMAUDIOSTREAMCFG streamCfg;
     1413        streamCfg.uHz           = 41000;
     1414        streamCfg.cChannels     = 2;
     1415        streamCfg.enmFormat     = AUD_FMT_S16;
     1416        streamCfg.enmEndianness = PDMAUDIOHOSTENDIANESS;
     1417
     1418        rc2 = audioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
     1419        AssertRC(rc2);
     1420
     1421        /* Add all required audio sinks. */
     1422        rc2 = audioMixerAddSink(pThis->pMixer, "[Playback] PCM Output",
     1423                                AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
     1424        AssertRC(rc2);
     1425    }
     1426#endif
    12831427}
    12841428
     
    13231467    {
    13241468        case 0x00:
    1325             reset_mixer(pThis);
     1469            sb16MixerReset(pThis);
    13261470            /* And update the actual volume, too. */
    13271471            fUpdateMaster = true;
     
    14981642}
    14991643
    1500 static int write_audio (PSB16STATE pThis, int nchan, int dma_pos,
    1501                         int dma_len, int len)
    1502 {
    1503     int temp, net;
    1504     uint8_t tmpbuf[_4K];
    1505 
    1506     temp = len;
    1507     net = 0;
    1508 
    1509     while (temp)
    1510     {
    1511         int left = dma_len - dma_pos;
     1644static int sb16WriteAudio(PSB16STATE pThis, int nchan, int dma_pos,
     1645                          int dma_len, int len)
     1646{
     1647    uint8_t tmpbuf[_4K]; /** @todo Have a buffer on the heap. */
     1648
     1649    int cbToWrite = len;
     1650    int cbWrittenTotal = 0;
     1651
     1652    while (cbToWrite)
     1653    {
    15121654#ifndef VBOX
    1513         size_t to_copy;
    1514         int copied;
    1515 #else
    1516         size_t to_copy;
    1517         uint32_t copied;
    1518 #endif
    1519 
    1520         to_copy = RT_MIN(temp, left);
    1521         if (to_copy > sizeof(tmpbuf))
    1522             to_copy = sizeof(tmpbuf);
     1655        size_t cbToRead;
     1656        int cbRead;
     1657#else
     1658        uint32_t cbWrittenMin = UINT32_MAX;
     1659        size_t cbToRead;
     1660        uint32_t cbRead;
     1661#endif
     1662        cbToRead = RT_MIN(dma_len - dma_pos, cbToWrite);
     1663        if (cbToRead > sizeof(tmpbuf))
     1664            cbToRead = sizeof(tmpbuf);
    15231665
    15241666#ifndef VBOX
    1525         copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
    1526 #else
    1527         int rc = PDMDevHlpDMAReadMemory(pThis->pDevIns, nchan, tmpbuf, dma_pos,
    1528                                         to_copy, &copied);
     1667        cbRead = DMA_read_memory (nchan, tmpbuf, dma_pos, cbToRead);
     1668#else
     1669        int rc = PDMDevHlpDMAReadMemory(pThis->pDevIns, nchan, tmpbuf, dma_pos, cbToRead, &cbRead);
    15291670        AssertMsgRC (rc, ("DMAReadMemory -> %Rrc\n", rc));
    15301671#endif
    15311672
    15321673#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1533         rc = pThis->pDrv->pfnWrite(pThis->pDrv, pThis->pGstStrmOut, tmpbuf, to_copy, &copied);
    1534         if (RT_FAILURE(rc))
    1535             break;
    1536 #else
    1537         copied = AUD_write (pThis->voice, tmpbuf, copied);
     1674        uint32_t cbWritten;
     1675
     1676        /* Just multiplex the output to the connected backends.
     1677         * No need to utilize the virtual mixer here (yet). */
     1678        PSB16DRIVER pDrv;
     1679        RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     1680        {
     1681            int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
     1682                                                 tmpbuf, cbToRead, &cbWritten);
     1683            AssertRCBreak(rc);
     1684            if (RT_FAILURE(rc2))
     1685                continue;
     1686
     1687            cbWrittenMin = RT_MIN(cbWrittenMin, cbWritten);
     1688            LogFlowFunc(("\tLUN#%RU8: cbWritten=%RU32, cWrittenMin=%RU32\n", pDrv->uLUN, cbWritten, cbWrittenMin));
     1689        }
     1690#else
     1691        cbWrittenMin = AUD_write (pThis->voice, tmpbuf, cbToRead);
    15381692#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    15391693
    1540         temp -= copied;
    1541         dma_pos = (dma_pos + copied) % dma_len;
    1542         net += copied;
    1543 
    1544         if (!copied)
    1545             break;
    1546     }
    1547 
    1548     return net;
     1694        cbToWrite      -= cbWrittenMin;
     1695        dma_pos         = (dma_pos + cbWrittenMin) % dma_len;
     1696        cbWrittenTotal += cbWrittenMin;
     1697
     1698        if (!cbRead)
     1699            break;
     1700    }
     1701
     1702    return cbWrittenTotal;
    15491703}
    15501704
    15511705#ifndef VBOX
    1552 static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
    1553 #else
    1554 static DECLCALLBACK(uint32_t) SB_read_DMA (PPDMDEVINS pDevIns, void *opaque, unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
    1555 #endif
    1556 {
    1557     PSB16STATE pThis = (SB16STATE*)opaque;
     1706static int sb16DMARead(void *opaque, int nchan, int dma_pos, int dma_len)
     1707#else
     1708static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
     1709#endif
     1710{
     1711    PSB16STATE pThis = (PSB16STATE)opaque;
    15581712    int till, copy, written, free;
    15591713
    1560     if (pThis->block_size <= 0) {
     1714    if (pThis->block_size <= 0)
     1715    {
    15611716        LogFlowFunc(("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
    15621717               pThis->block_size, nchan, dma_pos, dma_len));
     
    15641719    }
    15651720
    1566     if (pThis->left_till_irq < 0) {
     1721    if (pThis->left_till_irq < 0)
    15671722        pThis->left_till_irq = pThis->block_size;
    1568     }
    15691723
    15701724#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1571     if (pThis->pGstStrmOut) {
    1572 #else
    1573     if (pThis->voice) {
     1725    PSB16DRIVER pDrv;
     1726
     1727    uint32_t cbOutMin = UINT32_MAX;
     1728    uint32_t cbOut;
     1729    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     1730    {
     1731        int rc2 = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
     1732                                                   NULL /* pcbIn */, &cbOut, NULL /* pcSamplesLive */);
     1733        if (RT_SUCCESS(rc2))
     1734            cbOutMin = RT_MIN(cbOutMin, cbOut);
     1735    }
     1736
     1737    LogFlowFunc(("cbOutMin=%RU32\n", cbOutMin));
     1738    if (cbOutMin == UINT32_MAX)
     1739    {
     1740        free = dma_len;
     1741    }
     1742    else
     1743    {
     1744        free = cbOutMin & ~pThis->align; /** @todo int vs. uint32. */
     1745        if ((free <= 0) || !dma_len)
     1746            return dma_pos;
     1747    }
     1748#else
     1749    if (pThis->voice)
     1750    {
     1751        free = pThis->audio_free & ~pThis->align;
     1752        if ((free <= 0) || !dma_len)
     1753            return dma_pos;
     1754    }
     1755    else
     1756        free = dma_len;
    15741757#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    1575         free = pThis->audio_free & ~pThis->align;
    1576         if ((free <= 0) || !dma_len) {
    1577             return dma_pos;
    1578         }
    1579     }
    1580     else {
    1581         free = dma_len;
    1582     }
    15831758
    15841759    copy = free;
     
    15861761
    15871762#ifdef DEBUG_SB16_MOST
    1588     LogFlowFunc(("pos:%06d %d till:%d len:%d\n",
    1589            dma_pos, free, till, dma_len));
    1590 #endif
    1591 
    1592     if (copy >= till) {
    1593         if (0 == pThis->dma_auto) {
     1763    LogFlowFunc(("pos:%06d %d till:%d len:%d\n", dma_pos, free, till, dma_len));
     1764#endif
     1765
     1766    if (copy >= till)
     1767    {
     1768        if (0 == pThis->dma_auto)
     1769        {
    15941770            copy = till;
    1595         } else {
    1596             if( copy >= till + pThis->block_size ) {
    1597                 copy = till;    /* Make sure we won't skip IRQs. */
    1598             }
    15991771        }
    1600     }
    1601 
    1602     written = write_audio (pThis, nchan, dma_pos, dma_len, copy);
     1772        else
     1773        {
     1774            if (copy >= till + pThis->block_size)
     1775                copy = till; /* Make sure we won't skip IRQs. */
     1776        }
     1777    }
     1778
     1779    written = sb16WriteAudio(pThis, nchan, dma_pos, dma_len, copy);
    16031780    dma_pos = (dma_pos + written) % dma_len;
     1781    Assert(pThis->left_till_irq >= written);
    16041782    pThis->left_till_irq -= written;
    16051783
    1606     if (pThis->left_till_irq <= 0) {
     1784    if (pThis->left_till_irq <= 0)
     1785    {
    16071786        pThis->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
    16081787#ifndef VBOX
     
    16111790        PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
    16121791#endif
    1613         if (0 == pThis->dma_auto) {
    1614             control (pThis, 0);
    1615             speaker (pThis, 0);
     1792        if (0 == pThis->dma_auto)
     1793        {
     1794            sb16Control(pThis, 0);
     1795            sb16SpeakerControl(pThis, 0);
    16161796        }
    16171797    }
     
    16191799#ifdef DEBUG_SB16_MOST
    16201800    LogFlowFunc(("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
    1621             dma_pos, free, dma_len, pThis->left_till_irq, copy, written,
    1622             pThis->block_size));
    1623 #endif
    1624 
    1625     while (pThis->left_till_irq <= 0) {
    1626         pThis->left_till_irq = pThis->block_size + pThis->left_till_irq;
    1627     }
     1801                 dma_pos, free, dma_len, pThis->left_till_irq, copy, written,
     1802                 pThis->block_size));
     1803#endif
     1804
     1805    while (pThis->left_till_irq <= 0)
     1806        pThis->left_till_irq += pThis->block_size;
    16281807
    16291808    return dma_pos;
    16301809}
    16311810
    1632 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1633 static void sb16AudioCallback(void *pvContext, uint32_t cbFree)
    1634 #else
     1811#ifndef VBOX_WITH_PDM_AUDIO_DRIVER
    16351812static void sb16AudioCallback(void *pvContext, int cbFree)
    1636 #endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    1637 {
    1638     SB16STATE *pState = (SB16STATE*)pvContext;
     1813{
     1814    PSB16STATE pState = (PSB16STATE)pvContext;
    16391815    AssertPtrReturnVoid(pState);
    16401816    pState->audio_free = cbFree;
     
    16441820#endif
    16451821}
     1822#else
     1823static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
     1824{
     1825    PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
     1826    AssertPtrReturnVoid(pThis);
     1827
     1828    int rc = VINF_SUCCESS;
     1829
     1830    uint32_t cbInMax  = 0;
     1831    uint32_t cbOutMin = UINT32_MAX;
     1832
     1833    PSB16DRIVER pDrv;
     1834
     1835    uint32_t cbIn, cbOut, cSamplesLive;
     1836    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     1837    {
     1838        rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
     1839                                              &cbIn, &cbOut, &cSamplesLive);
     1840        if (RT_SUCCESS(rc))
     1841        {
     1842            LogFlowFunc(("\tLUN#%RU8: [1] cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, cbIn, cbOut));
     1843
     1844            if (cSamplesLive)
     1845            {
     1846                uint32_t cSamplesPlayed;
     1847                int rc2 = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, &cSamplesPlayed);
     1848                if (RT_SUCCESS(rc2))
     1849                    LogFlowFunc(("LUN#%RU8: cSamplesLive=%RU32, cSamplesPlayed=%RU32\n",
     1850                                 pDrv->uLUN, cSamplesLive, cSamplesPlayed));
     1851
     1852                if (cSamplesPlayed)
     1853                {
     1854                    rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
     1855                                                          &cbIn, &cbOut, &cSamplesLive);
     1856                    if (RT_SUCCESS(rc))
     1857                        LogFlowFunc(("\tLUN#%RU8: [2] cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, cbIn, cbOut));
     1858                }
     1859            }
     1860
     1861            cbInMax  = RT_MAX(cbInMax, cbIn);
     1862            cbOutMin = RT_MIN(cbOutMin, cbOut);
     1863        }
     1864    }
     1865
     1866    LogFlowFunc(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
     1867
     1868    if (cbOutMin == UINT32_MAX)
     1869        cbOutMin = 0;
     1870
     1871    /*
     1872     * Playback.
     1873     */
     1874    if (cbOutMin)
     1875    {
     1876        Assert(cbOutMin != UINT32_MAX);
     1877
     1878        /* New space available, see if we can transfer more. */
     1879        PDMDevHlpDMASchedule(pThis->pDevIns);
     1880    }
     1881
     1882    /*
     1883     * Recording.
     1884     */
     1885    /** @todo Implement recording. */
     1886
     1887    TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->uTicksIO);
     1888}
     1889#endif /* !VBOX_WITH_PDM_AUDIO_DRIVER */
    16461890
    16471891static void SB_save (QEMUFile *f, void *opaque)
     
    16501894    PSB16STATE pThis = opaque;
    16511895#else
    1652     PSB16STATE pThis = (SB16STATE *)opaque;
     1896    PSB16STATE pThis = (PSB16STATE)opaque;
    16531897#endif
    16541898
     
    17111955    }
    17121956#else
    1713     PSB16STATE pThis = (SB16STATE *)opaque;
     1957    PSB16STATE pThis = (PSB16STATE)opaque;
    17141958#endif
    17151959
     
    17632007
    17642008#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    1765     if (pThis->pGstStrmOut)
    1766     {
    1767         pThis->pDrv->pfnCloseOut(pThis->pDrv, pThis->pGstStrmOut);
    1768         pThis->pGstStrmOut = NULL;
     2009    PSB16DRIVER pDrv;
     2010    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     2011    {
     2012        if (pDrv->Out.pStrmOut)
     2013        {
     2014            pDrv->pConnector->pfnCloseOut(pThis->pDrv, pDrv->Out.pStrmOut);
     2015            pDrv->Out.pStrmOut = NULL;
     2016        }
    17692017    }
    17702018#else
     
    17862034            streamCfg.enmEndianness = PDMAUDIOHOSTENDIANESS;
    17872035
    1788             int rc = pThis->pDrv->pfnOpenOut(pThis->pDrv, "sb16.out", &streamCfg, &pThis->pGstStrmOut);
     2036            int rc = sb16OpenOut(pThis, &streamCfg);
    17892037            AssertRC(rc);
    17902038#else
     
    18052053        }
    18062054
    1807         control(pThis, 1);
    1808         speaker(pThis, pThis->speaker);
     2055        sb16Control(pThis, 1);
     2056        sb16SpeakerControl(pThis, pThis->speaker);
    18092057    }
    18102058
     
    18492097    pThis->csp_regs[9] = 0xf8;
    18502098
    1851     reset_mixer (pThis);
     2099    sb16MixerReset (pThis);
    18522100    pThis->aux_ts = qemu_new_timer (vm_clock, aux_timer, s);
    18532101    if (!pThis->aux_ts) {
     
    18682116    register_ioport_write (pThis->port + 0x5, 1, 1, mixer_write_datab, s);
    18692117
    1870     DMA_register_channel (pThis->hdma, SB_read_DMA, s);
    1871     DMA_register_channel (pThis->dma, SB_read_DMA, s);
     2118    DMA_register_channel (pThis->hdma, sb16DMARead, s);
     2119    DMA_register_channel (pThis->dma, sb16DMARead, s);
    18722120    pThis->can_write = 1;
    18732121
     
    18792127#else /* VBOX */
    18802128
    1881 
    1882 static DECLCALLBACK(int) sb16LiveExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
     2129static DECLCALLBACK(int) sb16LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
    18832130{
    18842131    PSB16STATE pThis = PDMINS_2_DATA (pDevIns, PSB16STATE);
     
    18922139}
    18932140
    1894 static DECLCALLBACK(int) sb16SaveExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
     2141static DECLCALLBACK(int) sb16SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
    18952142{
    18962143    PSB16STATE pThis = PDMINS_2_DATA (pDevIns, PSB16STATE);
     
    19012148}
    19022149
    1903 static DECLCALLBACK(int) sb16LoadExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM,
    1904                                        uint32_t uVersion, uint32_t uPass)
     2150static DECLCALLBACK(int) sb16LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
    19052151{
    19062152    PSB16STATE pThis = PDMINS_2_DATA (pDevIns, PSB16STATE);
     
    19442190}
    19452191
     2192static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg)
     2193{
     2194    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     2195    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
     2196
     2197    int rc = VINF_SUCCESS;
     2198
     2199    PSB16DRIVER pDrv;
     2200    uint8_t uLUN = 0;
     2201    char *pszDesc;
     2202    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     2203    {
     2204        if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] sb16.po", uLUN) <= 0)
     2205        {
     2206            rc = VERR_NO_MEMORY;
     2207            break;
     2208        }
     2209
     2210        int rc2 = pDrv->pConnector->pfnOpenOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
     2211        LogFlowFunc(("LUN#%RU8: Opened output with rc=%Rrc\n", uLUN, rc));
     2212        if (rc2 == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
     2213        {
     2214            audioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
     2215            rc = audioMixerAddStreamOut(pThis->pSinkOutput,
     2216                                        pDrv->pConnector, pDrv->Out.pStrmOut,
     2217                                        0 /* uFlags */,
     2218                                        &pDrv->Out.phStrmOut);
     2219        }
     2220
     2221        RTStrFree(pszDesc);
     2222
     2223        if (RT_FAILURE(rc2))
     2224        {
     2225            if (RT_SUCCESS(rc))
     2226                rc = rc2;
     2227            break;
     2228        }
     2229
     2230        uLUN++;
     2231    }
     2232
     2233    return rc;
     2234}
     2235
    19462236/**
    19472237 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
    19482238 */
    1949 static DECLCALLBACK(void *) sb16QueryInterface (struct PDMIBASE *pInterface,
    1950                                                 const char *pszIID)
     2239static DECLCALLBACK(void *) sb16QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
    19512240{
    19522241    PSB16STATE pThis = RT_FROM_MEMBER(pInterface, SB16STATE, IBase);
     
    19822271}
    19832272
    1984 static DECLCALLBACK(int) sb16Construct (PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
     2273static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
    19852274{
    19862275    PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
     
    20522341    pThis->csp_regs[9]             = 0xf8;
    20532342
    2054     reset_mixer(pThis);
     2343    sb16MixerReset(pThis);
    20552344
    20562345    /*
    2057      * Create timer, register & attach stuff.
     2346     * Create timer(s), register & attach stuff.
    20582347     */
    2059     rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16Timer, pThis,
    2060                                 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 timer", &pThis->pTimer);
     2348    rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIRQ, pThis,
     2349                                TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IRQ timer", &pThis->pTimerIRQ);
    20612350    if (RT_FAILURE(rc))
    2062         AssertMsgFailedReturn(("pfnTMTimerCreate -> %Rrc\n", rc), rc);
     2351        AssertMsgFailedReturn(("Error creating IRQ timer, rc=%Rrc\n", rc), rc);
     2352
     2353#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     2354    rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIO, pThis,
     2355                                TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IO timer", &pThis->pTimerIO);
     2356    if (RT_FAILURE(rc))
     2357        AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
     2358    else
     2359    {
     2360        pThis->uTicksIO = PDMDevHlpTMTimeVirtGetFreq(pDevIns) / 200; /** Hz. @todo Make this configurable! */
     2361        if (pThis->uTicksIO < 100)
     2362            pThis->uTicksIO = 100;
     2363        LogFunc(("I/O timer ticks=%RU64\n", pThis->uTicksIO));
     2364
     2365        /* Fire off timer. */
     2366        TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->uTicksIO);
     2367    }
     2368#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    20632369
    20642370    rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x04,  2, pThis,
     
    20712377        return rc;
    20722378
    2073     rc = PDMDevHlpDMARegister(pDevIns, pThis->hdma, SB_read_DMA, pThis);
     2379    rc = PDMDevHlpDMARegister(pDevIns, pThis->hdma, sb16DMARead, pThis);
    20742380    if (RT_FAILURE(rc))
    20752381        return rc;
    2076     rc = PDMDevHlpDMARegister(pDevIns, pThis->dma, SB_read_DMA, pThis);
     2382    rc = PDMDevHlpDMARegister(pDevIns, pThis->dma, sb16DMARead, pThis);
    20772383    if (RT_FAILURE(rc))
    20782384        return rc;
     
    20842390        return rc;
    20852391
     2392    /*
     2393     * Attach driver.
     2394     */
     2395#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
     2396    RTListInit(&pThis->lstDrv);
     2397
     2398    uint8_t uLUN;
     2399    for (uLUN = 0; uLUN < UINT8_MAX; uLUN)
     2400    {
     2401        LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
     2402        rc = sb16Attach(pDevIns, uLUN, PDM_TACH_FLAGS_NOT_HOT_PLUG);
     2403        if (RT_FAILURE(rc))
     2404        {
     2405            if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
     2406                rc = VINF_SUCCESS;
     2407            break;
     2408        }
     2409
     2410        uLUN++;
     2411    }
     2412
     2413    LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
     2414#else
    20862415    rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Audio Driver Port");
    2087 #ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    2088     if(RT_SUCCESS(rc))
    2089     {
    2090         pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIAUDIOCONNECTOR);
    2091         AssertMsgReturn(pThis->pDrv,
    2092                         ("Configuration error: instance %d has no host audio interface!\n", iInstance),
    2093                         VERR_PDM_MISSING_INTERFACE);
    2094     }
    2095     else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
    2096 #else
    20972416    if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
    2098 #endif
    2099         LogFunc(("No attached driver!\n"));
     2417        LogFunc(("ac97: No attached driver!\n"));
    21002418    else if (RT_FAILURE(rc))
    21012419    {
     
    21032421        return rc;
    21042422    }
     2423#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
    21052424
    21062425#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
    21072426    legacy_reset(pThis);
    21082427
    2109     if (!pThis->pDrv->pfnIsOutputOK(pThis->pDrv,pThis->pGstStrmOut))
    2110     {
    2111         LogRel(("SB16: WARNING: Unable to open PCM OUT!\n"));
    2112         pThis->pDrv->pfnCloseOut(pThis->pDrv, pThis->pGstStrmOut );
    2113         pThis->pGstStrmOut = NULL;
    2114 
    2115         pThis->pDrv->pfnInitNull(pThis->pDrv);
    2116 
    2117         PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
    2118             N_("No audio devices could be opened. Selecting the NULL audio backend "
    2119                "with the consequence that no sound is audible"));
     2428    PSB16DRIVER pDrv;
     2429    uLUN = 0;
     2430    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     2431    {
     2432        /*
     2433         * Only primary drivers are critical for the VM to run. Everything else
     2434         * might not worth showing an own error message box in the GUI.
     2435         */
     2436        if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
     2437            continue;
     2438
     2439        PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
     2440        AssertPtr(pCon);
     2441        if (!pCon->pfnIsOutputOK(pCon, pDrv->Out.pStrmOut))
     2442        {
     2443            LogRel(("SB16: WARNING: Unable to open PCM OUT!\n"));
     2444
     2445            pCon->pfnCloseOut(pCon, pDrv->Out.pStrmOut);
     2446            pDrv->Out.pStrmOut = NULL;
     2447
     2448            pThis->pDrv->pfnInitNull(pThis->pDrv);
     2449
     2450            PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
     2451                N_("No audio devices could be opened. Selecting the NULL audio backend "
     2452                   "with the consequence that no sound is audible"));
     2453        }
    21202454    }
    21212455#else
     
    21912525    PDM_DEVREG_VERSION
    21922526};
    2193 
    21942527#endif /* VBOX */
    21952528
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