VirtualBox

Ignore:
Timestamp:
Apr 30, 2021 12:39:40 PM (4 years ago)
Author:
vboxsync
Message:

Audio/SB16: More cleanups / todos. bugref:9890

File:
1 edited

Legend:

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

    r88773 r88797  
    6969*   Defined Constants And Macros                                                                                                 *
    7070*********************************************************************************************************************************/
     71/** Default timer frequency (in Hz). */
     72#define SB16_TIMER_HZ_DEFAULT           100
    7173/** The maximum number of separate streams we currently implement.
    7274 *  Currently we only support one stream only, namely the output stream. */
     
    196198} SB16STREAMDEBUG;
    197199
     200typedef struct SB16STREAMHWCFG
     201{
     202    uint8_t                         uIrq;
     203    uint8_t                         uDmaChanLow;
     204    uint8_t                         uDmaChanHigh;
     205    RTIOPORT                        uPort;
     206    uint16_t                        uVer;
     207} SB16STREAMHWCFG;
     208
    198209/**
    199210 * Structure for a SB16 stream.
     
    203214    /** The stream's own index in \a aStreams of SB16STATE.
    204215     *  Set to UINT8_MAX if not set (yet). */
    205     uint8_t                         uIdx;
     216    uint8_t                 uIdx;
     217    uint16_t                uTimerHz;
    206218    /** The timer for pumping data thru the attached LUN drivers. */
    207     TMTIMERHANDLE                   hTimerIO;
     219    TMTIMERHANDLE           hTimerIO;
    208220    /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
    209     uint64_t                        cTicksTimerIOInterval;
     221    uint64_t                cTicksTimerIOInterval;
    210222    /** Timestamp of the last timer callback (sb16TimerIO).
    211      * Used to calculate the time actually elapsed between two timer callbacks.
     223     * Used to calculate thetime actually elapsed between two timer callbacks.
    212224     * This currently ASSMUMES that we only have one single (output) stream. */
    213     uint64_t                        tsTimerIO; /** @todo Make this a per-stream value. */
    214     /** The stream's current configuration. */
    215     PDMAUDIOSTREAMCFG               Cfg;
     225    uint64_t                tsTimerIO; /** @todo Make this a per-stream value. */
     226    /** The stream's currentconfiguration. */
     227    PDMAUDIOSTREAMCFG       Cfg;
     228    /** The stream's defaulthardware configuration, mostly done by jumper settings back then. */
     229    SB16STREAMHWCFG         HwCfgDefault;
     230    /** The stream's hardware configuration set at runtime.
     231     *  Might differ from the default configuration above and is needed for live migration. */
     232    SB16STREAMHWCFG         HwCfgRuntime;
     233
     234    int                     fifo;
     235    int                     dma_auto;
     236    /** Whether to use the high (\c true) or the low (\c false) DMA channel. */
     237    int                     fDmaUseHigh;
     238    int                     can_write; /** @todo r=andy BUGBUG Value never gets set to 0! */
     239    int                     time_const;
     240    /** The DMA transfer (block)size in bytes. */
     241    int32_t                 cbDmaBlockSize;
     242    int32_t                 cbDmaLeft; /** Note: Can be < 0. Needs to 32-bit for backwards compatibility. */
    216243    /** Internal state of this stream. */
    217     SB16STREAMSTATE                 State;
     244    SB16STREAMSTATE         State;
    218245    /** Debug stuff. */
    219     SB16STREAMDEBUG                 Dbg;
     246    SB16STREAMDEBUG         Dbg;
    220247} SB16STREAM;
    221248/** Pointer to a SB16 stream */
     
    255282typedef struct SB16STATE
    256283{
    257 #ifdef VBOX
    258284    /** Pointer to the device instance. */
    259     PPDMDEVINSR3        pDevInsR3;
     285    PPDMDEVINSR3           pDevInsR3;
    260286    /** Pointer to the connector of the attached audio driver. */
    261     PPDMIAUDIOCONNECTOR pDrv;
    262     int irqCfg;
    263     int dmaCfg;
    264     int hdmaCfg;
    265     int portCfg;
    266     int verCfg;
    267 #endif
    268     int irq;
    269     int dma;
    270     int hdma;
    271     int port;
    272     int ver;
    273 
    274     int dsp_in_idx;
    275     int dsp_out_data_len;
    276     int fmt_stereo;
    277     int fmt_signed;
    278     int fmt_bits;
    279     PDMAUDIOFMT fmt;
    280     int dma_auto;
    281     int block_size;
    282     int fifo;
    283     int freq;
    284     int time_const;
    285     int speaker;
    286     int dsp_in_needed_bytes;
    287     int cmd;
    288     int use_hdma;
    289     int highspeed;
    290     int can_write; /** @todo r=andy BUGBUG Value never gets set to 0! */
    291 
    292     int v2x6;
    293 
    294     uint8_t csp_param;
    295     uint8_t csp_value;
    296     uint8_t csp_mode;
    297     uint8_t csp_index;
    298     uint8_t csp_regs[256];
    299     uint8_t csp_reg83[4];
    300     int csp_reg83r;
    301     int csp_reg83w;
    302 
    303     uint8_t dsp_in_data[10];
    304     uint8_t dsp_out_data[50];
    305     uint8_t test_reg;
    306     uint8_t last_read_byte;
    307     int nzero;
    308 
    309     int left_till_irq; /** Note: Can be < 0. */
    310 
    311     int dma_running;
    312     int bytes_per_second;
    313     int align;
    314 
    315     RTLISTANCHOR        lstDrv;
     287    PPDMIAUDIOCONNECTOR    pDrv;
     288
     289    int                    dsp_in_idx;
     290    int                    dsp_out_data_len;
     291    int                    dsp_in_needed_bytes;
     292    int                    cmd;
     293    int                    highspeed;
     294
     295    int                    v2x6;
     296
     297    uint8_t                csp_param;
     298    uint8_t                csp_value;
     299    uint8_t                csp_mode;
     300    uint8_t                csp_index;
     301    uint8_t                csp_regs[256];
     302    uint8_t                csp_reg83[4];
     303    int                    csp_reg83r;
     304    int                    csp_reg83w;
     305
     306    uint8_t                dsp_in_data[10];
     307    uint8_t                dsp_out_data[50];
     308    uint8_t                test_reg;
     309    uint8_t                last_read_byte;
     310    int                    nzero;
     311
     312    RTLISTANCHOR           lstDrv;
    316313    /** IRQ timer   */
    317     TMTIMERHANDLE       hTimerIRQ;
     314    TMTIMERHANDLE          hTimerIRQ;
    318315    /** The base interface for LUN\#0. */
    319     PDMIBASE            IBase;
     316    PDMIBASE               IBase;
    320317
    321318    /** Array of all SB16 hardware audio stream. */
     
    327324
    328325    /** The two mixer I/O ports (port + 4). */
    329     IOMIOPORTHANDLE     hIoPortsMixer;
     326    IOMIOPORTHANDLE        hIoPortsMixer;
    330327    /** The 10 DSP I/O ports (port + 6). */
    331     IOMIOPORTHANDLE     hIoPortsDsp;
     328    IOMIOPORTHANDLE        hIoPortsDsp;
    332329
    333330    /** Debug settings. */
    334     SB16STATEDEBUG                  Dbg;
     331    SB16STATEDEBUG         Dbg;
    335332
    336333    /* mixer state */
    337     uint8_t mixer_nreg;
    338     uint8_t mixer_regs[256];
     334    uint8_t                mixer_nreg;
     335    uint8_t                mixer_regs[256];
    339336
    340337#ifdef VBOX_WITH_STATISTICS
    341     STAMPROFILE             StatTimerIO;
    342     STAMCOUNTER             StatBytesRead;
     338    STAMPROFILE            StatTimerIO;
     339    STAMCOUNTER            StatBytesRead;
    343340#endif
    344341} SB16STATE;
     
    369366#endif /* VBOX_WITH_AUDIO_SB16_ASYNC_IO */
    370367
    371 static void sb16SpeakerControl(PSB16STATE pThis, int on);
     368static void sb16SpeakerControl(PSB16STATE pThis, bool fOn);
    372369static void sb16UpdateVolume(PSB16STATE pThis);
    373370
    374 #if 0 // unused // def DEBUG
    375 DECLINLINE(void) log_dsp(PSB16STATE pThis)
    376 {
    377     LogFlowFunc(("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
    378                  pThis->fmt_stereo ? "Stereo" : "Mono",
    379                  pThis->fmt_signed ? "Signed" : "Unsigned",
    380                  pThis->fmt_bits,
    381                  pThis->dma_auto ? "Auto" : "Single",
    382                  pThis->block_size,
    383                  pThis->freq,
    384                  pThis->time_const,
    385                  pThis->speaker));
    386 }
    387 #endif
    388371
    389372#ifdef VBOX_WITH_AUDIO_SB16_ASYNC_IO
     
    545528#endif /* VBOX_WITH_AUDIO_SB16_ASYNC_IO */
    546529
    547 static void sb16SpeakerControl(PSB16STATE pThis, int on)
    548 {
    549     pThis->speaker = on;
    550 }
    551 
    552 static void sb16Control(PPDMDEVINS pDevIns, PSB16STATE pThis, int hold)
    553 {
    554     int dma = pThis->use_hdma ? pThis->hdma : pThis->dma;
    555     pThis->dma_running = hold;
    556 
    557     LogFlowFunc(("hold %d high %d dma %d\n", hold, pThis->use_hdma, dma));
    558 
    559     PDMDevHlpDMASetDREQ(pThis->pDevInsR3, dma, hold);
    560 
    561     /* We only support one output stream at the moment, so keep things simple here for now. */
    562     PSB16STREAM pStream = &pThis->aStreams[SB16_IDX_OUT];
    563 
    564     if (hold)
    565     {
    566         int rc = VINF_SUCCESS;
    567 
    568         if (pThis->freq > 0)
     530static void sb16SpeakerControl(PSB16STATE pThis, bool fOn)
     531{
     532    RT_NOREF(pThis, fOn);
     533
     534    /** @todo This currently does nothing. */
     535}
     536
     537static void sb16StreamControl(PPDMDEVINS pDevIns, PSB16STATE pThis, PSB16STREAM pStream, bool fRun)
     538{
     539    unsigned uDmaChan = pStream->fDmaUseHigh ? pStream->HwCfgRuntime.uDmaChanHigh : pStream->HwCfgRuntime.uDmaChanLow;
     540
     541    LogFunc(("fRun=%RTbool, fDmaUseHigh=%RTbool, uDmaChan=%u\n", fRun, pStream->fDmaUseHigh, uDmaChan));
     542
     543    PDMDevHlpDMASetDREQ(pThis->pDevInsR3, uDmaChan, fRun ? 1 : 0);
     544
     545    if (fRun != pStream->State.fEnabled)
     546    {
     547        if (fRun)
    569548        {
    570             rc = sb16StreamOpen(pDevIns, pThis, pStream);
    571             if (RT_SUCCESS(rc))
    572                 sb16UpdateVolume(pThis);
    573         }
    574 
    575         if (RT_SUCCESS(rc))
    576         {
    577             rc = sb16StreamEnable(pThis, pStream, true /* fEnable */, false /* fForce */);
     549            int rc = VINF_SUCCESS;
     550
     551            if (pStream->Cfg.Props.uHz > 0)
     552            {
     553                rc = sb16StreamOpen(pDevIns, pThis, pStream);
     554                if (RT_SUCCESS(rc))
     555                    sb16UpdateVolume(pThis);
     556            }
     557            else
     558                AssertFailed(); /** @todo Buggy code? */
     559
    578560            if (RT_SUCCESS(rc))
    579561            {
    580                 sb16TimerSet(pDevIns, pStream, pStream->cTicksTimerIOInterval);
    581 
    582                 PDMDevHlpDMASchedule(pThis->pDevInsR3);
     562                rc = sb16StreamEnable(pThis, pStream, true /* fEnable */, false /* fForce */);
     563                if (RT_SUCCESS(rc))
     564                {
     565                    sb16TimerSet(pDevIns, pStream, pStream->cTicksTimerIOInterval);
     566
     567                    PDMDevHlpDMASchedule(pThis->pDevInsR3);
     568                }
    583569            }
    584570        }
    585     }
    586     else
    587     {
    588         sb16StreamEnable(pThis, pStream, false /* fEnable */, false /* fForce */);
     571        else
     572        {
     573            sb16StreamEnable(pThis, pStream, false /* fEnable */, false /* fForce */);
     574        }
    589575    }
    590576}
     
    593579#define DMA8_HIGH 2
    594580
    595 static void continue_dma8(PPDMDEVINS pDevIns, PSB16STATE pThis)
    596 {
    597     sb16Control(pDevIns, pThis, 1);
    598 }
    599 
    600 static void dma_cmd8(PPDMDEVINS pDevIns, PSB16STATE pThis, int mask, int dma_len)
    601 {
    602     pThis->fmt        = PDMAUDIOFMT_U8;
    603     pThis->use_hdma   = 0;
    604     pThis->fmt_bits   = 8;
    605     pThis->fmt_signed = 0;
    606     pThis->fmt_stereo = (pThis->mixer_regs[0x0e] & 2) != 0;
    607 
    608     if (-1 == pThis->time_const)
    609     {
    610         if (pThis->freq <= 0)
    611             pThis->freq = 11025;
     581static void sb16DmaCmdContinue8(PPDMDEVINS pDevIns, PSB16STATE pThis, PSB16STREAM pStream)
     582{
     583    sb16StreamControl(pDevIns, pThis, pStream, true /* fRun */);
     584}
     585
     586static void sb16DmaCmd8(PPDMDEVINS pDevIns, PSB16STATE pThis, PSB16STREAM pStream,
     587                        int mask, int dma_len)
     588{
     589    pStream->fDmaUseHigh = 0;
     590
     591    if (-1 == pStream->time_const)
     592    {
     593        if (pStream->Cfg.Props.uHz == 0)
     594            pStream->Cfg.Props.uHz = 11025;
    612595    }
    613596    else
    614597    {
    615         int tmp = (256 - pThis->time_const);
    616         pThis->freq = (1000000 + (tmp / 2)) / tmp;
    617     }
     598        int tmp = (256 - pStream->time_const);
     599        pStream->Cfg.Props.uHz = (1000000 + (tmp / 2)) / tmp;
     600    }
     601
     602    unsigned cShiftChannels = pStream->Cfg.Props.cChannelsX >= 2 ? 1 : 0;
    618603
    619604    if (dma_len != -1)
    620605    {
    621         pThis->block_size = dma_len << pThis->fmt_stereo;
     606        pStream->cbDmaBlockSize = dma_len << cShiftChannels;
    622607    }
    623608    else
     
    632617           Both use stereo, and Creatives own documentation states that
    633618           0x48 sets block size in bytes less one.. go figure */
    634         pThis->block_size &= ~pThis->fmt_stereo;
    635     }
    636 
    637     pThis->freq >>= pThis->fmt_stereo;
    638     pThis->left_till_irq = pThis->block_size;
    639     pThis->bytes_per_second = (pThis->freq << pThis->fmt_stereo);
     619        pStream->cbDmaBlockSize &= ~cShiftChannels;
     620    }
     621
     622    pStream->Cfg.Props.uHz >>= cShiftChannels;
     623    pStream->cbDmaLeft = pStream->cbDmaBlockSize;
    640624    /* pThis->highspeed = (mask & DMA8_HIGH) != 0; */
    641     pThis->dma_auto = (mask & DMA8_AUTO) != 0;
    642     pThis->align = (1 << pThis->fmt_stereo) - 1;
    643 
    644     if (pThis->block_size & pThis->align)
    645         LogFlowFunc(("warning: misaligned block size %d, alignment %d\n", pThis->block_size, pThis->align + 1));
    646 
    647     LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, dma %d, auto %d, fifo %d, high %d\n",
    648                  pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
    649                  pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
    650 
    651     continue_dma8(pDevIns, pThis);
     625    pStream->dma_auto = (mask & DMA8_AUTO) != 0;
     626
     627    PDMAudioPropsInit(&pStream->Cfg.Props, 1                     /* 8-bit */,
     628                      false                                      /* fSigned */,
     629                      (pThis->mixer_regs[0x0e] & 2) == 0 ? 1 : 2 /* Mono/Stereo */,
     630                      pStream->Cfg.Props.uHz);
     631
     632    /** @todo Check if stream's DMA block size is properly aligned to the set PCM props. */
     633
     634    sb16DmaCmdContinue8(pDevIns, pThis, pStream);
    652635    sb16SpeakerControl(pThis, 1);
    653636}
    654637
    655 static void dma_cmd(PPDMDEVINS pDevIns, PSB16STATE pThis, uint8_t cmd, uint8_t d0, int dma_len)
    656 {
    657     pThis->use_hdma   = cmd < 0xc0;
    658     pThis->fifo       = (cmd >> 1) & 1;
    659     pThis->dma_auto   = (cmd >> 2) & 1;
    660     pThis->fmt_signed = (d0 >> 4) & 1;
    661     pThis->fmt_stereo = (d0 >> 5) & 1;
     638static void sb16DmaCmd(PPDMDEVINS pDevIns, PSB16STATE pThis, PSB16STREAM pStream,
     639                       uint8_t cmd, uint8_t d0, int dma_len)
     640{
     641    pStream->fDmaUseHigh   = cmd < 0xc0;
     642    pStream->fifo       = (cmd >> 1) & 1;
     643    pStream->dma_auto   = (cmd >> 2) & 1;
     644
     645    pStream->Cfg.Props.fSigned    = RT_BOOL((d0 >> 4) & 1); /** @todo Use RT_BIT? */
     646    pStream->Cfg.Props.cChannelsX = (d0 >> 5) & 1 ? 2 : 1;
    662647
    663648    switch (cmd >> 4)
    664649    {
    665650        case 11:
    666             pThis->fmt_bits = 16;
     651            pStream->Cfg.Props.cbSampleX = 2 /* 16 bit */;
    667652            break;
    668653
    669654        case 12:
    670             pThis->fmt_bits = 8;
    671             break;
    672     }
    673 
    674     if (-1 != pThis->time_const)
     655            pStream->Cfg.Props.cbSampleX = 1 /* 8 bit */;
     656            break;
     657
     658        default:
     659            AssertFailed();
     660            break;
     661    }
     662
     663    if (-1 != pStream->time_const)
    675664    {
    676665#if 1
    677         int tmp = 256 - pThis->time_const;
    678         pThis->freq = (1000000 + (tmp / 2)) / tmp;
     666        int tmp = 256 - pStream->time_const;
     667        pStream->Cfg.Props.uHz = (1000000 + (tmp / 2)) / tmp;
    679668#else
    680         /* pThis->freq = 1000000 / ((255 - pThis->time_const) << pThis->fmt_stereo); */
    681         pThis->freq = 1000000 / ((255 - pThis->time_const));
     669        /* pThis->freq = 1000000 / ((255 - pStream->time_const) << pThis->fmt_stereo); */
     670        pThis->freq = 1000000 / ((255 - pStream->time_const));
    682671#endif
    683         pThis->time_const = -1;
    684     }
    685 
    686     pThis->block_size = dma_len + 1;
    687     pThis->block_size <<= ((pThis->fmt_bits == 16) ? 1 : 0);
    688     if (!pThis->dma_auto)
     672        pStream->time_const = -1;
     673    }
     674
     675    pStream->cbDmaBlockSize = dma_len + 1;
     676    pStream->cbDmaBlockSize <<= ((pStream->Cfg.Props.cbSampleX == 2) ? 1 : 0);
     677    if (!pStream->dma_auto)
    689678    {
    690679        /*
     
    694683         * wonders of SB16 yet again.
    695684         */
    696         pThis->block_size <<= pThis->fmt_stereo;
    697     }
    698 
    699     LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, dma %d, auto %d, fifo %d, high %d\n",
    700                  pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
    701                  pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
    702 
    703     if (16 == pThis->fmt_bits)
    704         pThis->fmt = pThis->fmt_signed ? PDMAUDIOFMT_S16 : PDMAUDIOFMT_U16;
    705     else
    706         pThis->fmt = pThis->fmt_signed ? PDMAUDIOFMT_S8 : PDMAUDIOFMT_U8;
    707 
    708     pThis->left_till_irq = pThis->block_size;
    709 
    710     pThis->bytes_per_second = (pThis->freq << pThis->fmt_stereo) << ((pThis->fmt_bits == 16) ? 1 : 0);
     685        pStream->cbDmaBlockSize <<= pStream->Cfg.Props.cChannelsX == 2 ? 1 : 0;
     686    }
     687
     688    pStream->cbDmaLeft = pStream->cbDmaBlockSize;
     689
    711690    pThis->highspeed = 0;
    712     pThis->align = (1 << (pThis->fmt_stereo + (pThis->fmt_bits == 16))) - 1;
    713     if (pThis->block_size & pThis->align)
    714     {
    715         LogFlowFunc(("warning: misaligned block size %d, alignment %d\n",
    716                      pThis->block_size, pThis->align + 1));
    717     }
    718 
    719     sb16Control(pDevIns, pThis, 1);
     691
     692    /** @todo Check if stream's DMA block size is properly aligned to the set PCM props. */
     693
     694    sb16StreamControl(pDevIns, pThis, pStream, true /* fRun */);
    720695    sb16SpeakerControl(pThis, 1);
    721696}
    722697
    723 static inline void dsp_set_data(PSB16STATE pThis, uint8_t val)
     698static inline void sb16DspSeData(PSB16STATE pThis, uint8_t val)
    724699{
    725700    LogFlowFunc(("%#x\n", val));
     
    728703}
    729704
    730 static inline uint8_t dsp_get_data(PSB16STATE pThis)
     705static inline uint8_t sb16DspGetData(PSB16STATE pThis)
    731706{
    732707    if (pThis->dsp_in_idx)
     
    736711}
    737712
    738 static void sb16HandleCommand(PPDMDEVINS pDevIns, PSB16STATE pThis, uint8_t cmd)
     713static void sb16DspCmdLookup(PPDMDEVINS pDevIns, PSB16STATE pThis, PSB16STREAM pStream, uint8_t cmd)
    739714{
    740715    LogFlowFunc(("command %#x\n", cmd));
     
    760735        pThis->dsp_in_needed_bytes = 0;
    761736
     737        /** @todo Use a mapping table with
     738         *        - a command verb (binary search)
     739         *        - required bytes
     740         *        - function callback handler
     741         */
     742
    762743        switch (cmd)
    763744        {
    764             case 0x03:
    765                 dsp_set_data(pThis, 0x10); /* pThis->csp_param); */
     745            case 0x03:              /* ASP Status */
     746                sb16DspSeData(pThis, 0x10); /* pThis->csp_param); */
    766747                goto warn;
    767748
    768             case 0x04:
     749            case 0x04:              /* DSP Status (Obsolete) / ASP ??? */
    769750                pThis->dsp_in_needed_bytes = 1;
    770751                goto warn;
    771752
    772             case 0x05:
     753            case 0x05:              /* ASP ??? */
    773754                pThis->dsp_in_needed_bytes = 2;
    774755                goto warn;
    775756
    776             case 0x08:
     757            case 0x08:              /* ??? */
    777758                /* __asm__ ("int3"); */
    778759                goto warn;
    779760
    780             case 0x0e:
     761            case 0x09:              /* ??? */
     762                sb16DspSeData(pThis, 0xf8);
     763                goto warn;
     764
     765            case 0x0e:              /* ??? */
    781766                pThis->dsp_in_needed_bytes = 2;
    782767                goto warn;
    783768
    784             case 0x09:
    785                 dsp_set_data(pThis, 0xf8);
    786                 goto warn;
    787 
    788             case 0x0f:
     769            case 0x0f:              /* ??? */
    789770                pThis->dsp_in_needed_bytes = 1;
    790771                goto warn;
    791772
    792             case 0x10:
     773            case 0x10:              /* Direct mode DAC */
    793774                pThis->dsp_in_needed_bytes = 1;
    794775                goto warn;
    795776
    796             case 0x14:
     777            case 0x14:              /* DAC DMA, 8-bit, uncompressed */
    797778                pThis->dsp_in_needed_bytes = 2;
    798                 pThis->block_size = 0;
     779                pStream->cbDmaBlockSize = 0;
    799780                break;
    800781
    801782            case 0x1c:              /* Auto-Initialize DMA DAC, 8-bit */
    802                 dma_cmd8(pDevIns, pThis, DMA8_AUTO, -1);
     783                sb16DmaCmd8(pDevIns, pThis, pStream, DMA8_AUTO, -1);
    803784                break;
    804785
    805786            case 0x20:              /* Direct ADC, Juice/PL */
    806                 dsp_set_data(pThis, 0xff);
     787                sb16DspSeData(pThis, 0xff);
    807788                goto warn;
    808789
    809             case 0x35:
    810                 LogFlowFunc(("0x35 - MIDI command not implemented\n"));
    811                 break;
    812 
    813             case 0x40:
    814                 pThis->freq = -1;
    815                 pThis->time_const = -1;
     790            case 0x35:              /* MIDI Read Interrupt + Write Poll (UART) */
     791                LogRelMax2(32, ("SB16: MIDI support not implemented yet\n"));
     792                break;
     793
     794            case 0x40:              /* Set Time Constant */
     795                pStream->time_const = -1;
    816796                pThis->dsp_in_needed_bytes = 1;
    817797                break;
    818798
    819             case 0x41:
    820                 pThis->freq = -1;
    821                 pThis->time_const = -1;
     799            case 0x41:              /* Set sample rate for input */
     800                pStream->Cfg.Props.uHz = 0; /** @todo r=andy Why do we reset output stuff here? */
     801                pStream->time_const = -1;
    822802                pThis->dsp_in_needed_bytes = 2;
    823803                break;
    824804
    825             case 0x42:
    826                 pThis->freq = -1;
    827                 pThis->time_const = -1;
     805            case 0x42:             /* Set sample rate for output */
     806                pStream->Cfg.Props.uHz = 0;
     807                pStream->time_const = -1;
    828808                pThis->dsp_in_needed_bytes = 2;
    829809                goto warn;
    830810
    831             case 0x45:
    832                 dsp_set_data(pThis, 0xaa);
     811            case 0x45:             /* Continue Auto-Initialize DMA, 8-bit */
     812                sb16DspSeData(pThis, 0xaa);
    833813                goto warn;
    834814
    835             case 0x47:                /* Continue Auto-Initialize DMA 16bit */
    836                 break;
    837 
    838             case 0x48:
     815            case 0x47:             /* Continue Auto-Initialize DMA, 16-bit */
     816                break;
     817
     818            case 0x48:             /* Set DMA Block Size */
    839819                pThis->dsp_in_needed_bytes = 2;
    840820                break;
    841821
    842             case 0x74:
    843                 pThis->dsp_in_needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
    844                 LogFlowFunc(("0x75 - DMA DAC, 4-bit ADPCM not implemented\n"));
     822            case 0x74:             /* DMA DAC, 4-bit ADPCM */
     823                pThis->dsp_in_needed_bytes = 2;
     824                LogFlowFunc(("4-bit ADPCM not implemented yet\n"));
    845825                break;
    846826
    847827            case 0x75:              /* DMA DAC, 4-bit ADPCM Reference */
    848828                pThis->dsp_in_needed_bytes = 2;
    849                 LogFlowFunc(("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n"));
     829                LogFlowFunc(("DMA DAC, 4-bit ADPCM Reference not implemented\n"));
    850830                break;
    851831
    852832            case 0x76:              /* DMA DAC, 2.6-bit ADPCM */
    853833                pThis->dsp_in_needed_bytes = 2;
    854                 LogFlowFunc(("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n"));
     834                LogFlowFunc(("DMA DAC, 2.6-bit ADPCM not implemented yet\n"));
    855835                break;
    856836
    857837            case 0x77:              /* DMA DAC, 2.6-bit ADPCM Reference */
    858838                pThis->dsp_in_needed_bytes = 2;
    859                 LogFlowFunc(("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n"));
    860                 break;
    861 
    862             case 0x7d:
    863                 LogFlowFunc(("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n"));
    864                 LogFlowFunc(("not implemented\n"));
    865                 break;
    866 
    867             case 0x7f:
    868                 LogFlowFunc(("0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"));
    869                 LogFlowFunc(("not implemented\n"));
    870                 break;
    871 
    872             case 0x80:
     839                LogFlowFunc(("ADPCM reference not implemented yet\n"));
     840                break;
     841
     842            case 0x7d:              /* Auto-Initialize DMA DAC, 4-bit ADPCM Reference */
     843                LogFlowFunc(("Autio-Initialize DMA DAC, 4-bit ADPCM reference not implemented yet\n"));
     844                break;
     845
     846            case 0x7f:              /* Auto-Initialize DMA DAC, 16-bit ADPCM Reference */
     847                LogFlowFunc(("Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference not implemented yet\n"));
     848                break;
     849
     850            case 0x80:              /* Silence DAC */
    873851                pThis->dsp_in_needed_bytes = 2;
    874852                break;
    875853
    876             case 0x90:
    877             case 0x91:
    878                 dma_cmd8(pDevIns, pThis, (((cmd & 1) == 0) ? 1 : 0) | DMA8_HIGH, -1);
    879                 break;
    880 
    881             case 0xd0:              /* halt DMA operation. 8bit */
    882                 sb16Control(pDevIns, pThis, 0);
    883                 break;
    884 
    885             case 0xd1:              /* speaker on */
    886                 sb16SpeakerControl(pThis, 1);
    887                 break;
    888 
    889             case 0xd3:              /* speaker off */
    890                 sb16SpeakerControl(pThis, 0);
    891                 break;
    892 
    893             case 0xd4:              /* continue DMA operation. 8bit */
     854            case 0x90:              /* Auto-Initialize DMA DAC, 8-bit (High Speed) */
     855                RT_FALL_THROUGH();
     856            case 0x91:              /* Normal DMA DAC, 8-bit (High Speed) */
     857                sb16DmaCmd8(pDevIns, pThis, pStream, (((cmd & 1) == 0) ? 1 : 0) | DMA8_HIGH, -1);
     858                break;
     859
     860            case 0xd0:              /* Halt DMA operation. 8bit */
     861                sb16StreamControl(pDevIns, pThis, pStream, false /* fRun */);
     862                break;
     863
     864            case 0xd1:              /* Speaker on */
     865                sb16SpeakerControl(pThis, true /* fOn */);
     866                break;
     867
     868            case 0xd3:              /* Speaker off */
     869                sb16SpeakerControl(pThis, false /* fOn */);
     870                break;
     871
     872            case 0xd4:              /* Continue DMA operation, 8-bit */
    894873                /* KQ6 (or maybe Sierras audblst.drv in general) resets
    895874                   the frequency between halt/continue */
    896                 continue_dma8(pDevIns, pThis);
    897                 break;
    898 
    899             case 0xd5:              /* halt DMA operation. 16bit */
    900                 sb16Control(pDevIns, pThis, 0);
    901                 break;
    902 
    903             case 0xd6:              /* continue DMA operation. 16bit */
    904                 sb16Control(pDevIns, pThis, 1);
    905                 break;
    906 
    907             case 0xd9:              /* exit auto-init DMA after this block. 16bit */
    908                 pThis->dma_auto = 0;
    909                 break;
    910 
    911             case 0xda:              /* exit auto-init DMA after this block. 8bit */
    912                 pThis->dma_auto = 0;
     875                sb16DmaCmdContinue8(pDevIns, pThis, pStream);
     876                break;
     877
     878            case 0xd5:              /* Halt DMA operation, 16-bit */
     879                sb16StreamControl(pDevIns, pThis, pStream, false /* fRun */);
     880                break;
     881
     882            case 0xd6:              /* Continue DMA operation, 16-bit */
     883                sb16StreamControl(pDevIns, pThis, pStream, true /* fRun */);
     884                break;
     885
     886            case 0xd9:              /* Exit auto-init DMA after this block, 16-bit */
     887                pStream->dma_auto = 0;
     888                break;
     889
     890            case 0xda:              /* Exit auto-init DMA after this block, 8-bit */
     891                pStream->dma_auto = 0;
    913892                break;
    914893
     
    917896                break;
    918897
    919             case 0xe1:
    920                 dsp_set_data(pThis, pThis->ver & 0xff);
    921                 dsp_set_data(pThis, pThis->ver >> 8);
    922                 break;
    923 
    924             case 0xe2:
     898            case 0xe1:              /* DSP version */
     899                sb16DspSeData(pThis, RT_LO_U8(pStream->HwCfgRuntime.uVer));
     900                sb16DspSeData(pThis, RT_HI_U8(pStream->HwCfgRuntime.uVer));
     901                break;
     902
     903            case 0xe2:              /* ??? */
    925904                pThis->dsp_in_needed_bytes = 1;
    926905                goto warn;
    927906
    928             case 0xe3:
     907            case 0xe3:              /* DSP copyright */
    929908            {
    930                 for (int i = sizeof (e3) - 1; i >= 0; --i)
    931                     dsp_set_data(pThis, e3[i]);
    932 
     909                for (int i = sizeof(e3) - 1; i >= 0; --i)
     910                    sb16DspSeData(pThis, e3[i]);
    933911                break;
    934912            }
    935913
    936             case 0xe4:              /* write test reg */
     914            case 0xe4:              /* Write test register */
    937915                pThis->dsp_in_needed_bytes = 1;
    938916                break;
    939917
    940             case 0xe7:
     918            case 0xe7:              /* ??? */
    941919                LogFlowFunc(("Attempt to probe for ESS (0xe7)?\n"));
    942920                break;
    943921
    944             case 0xe8:              /* read test reg */
    945                 dsp_set_data(pThis, pThis->test_reg);
    946                 break;
    947 
    948             case 0xf2:
    949             case 0xf3:
    950                 dsp_set_data(pThis, 0xaa);
     922            case 0xe8:              /* Read test register */
     923                sb16DspSeData(pThis, pThis->test_reg);
     924                break;
     925
     926            case 0xf2:              /* IRQ Request, 8-bit */
     927                RT_FALL_THROUGH();
     928            case 0xf3:              /* IRQ Request, 16-bit */
     929            {
     930                sb16DspSeData(pThis, 0xaa);
    951931                pThis->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
    952                 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
    953                 break;
    954 
    955             case 0xf8:
    956                 /* Undocumented, used by old Creative diagnostic programs. */
    957                 dsp_set_data(pThis, 0);
     932                PDMDevHlpISASetIrq(pThis->pDevInsR3, pStream->HwCfgRuntime.uIrq, 1);
     933                break;
     934            }
     935
     936            case 0xf8:              /* Undocumented, used by old Creative diagnostic programs */
     937                sb16DspSeData(pThis, 0);
    958938                goto warn;
    959939
    960             case 0xf9:
     940            case 0xf9:              /* ??? */
    961941                pThis->dsp_in_needed_bytes = 1;
    962942                goto warn;
    963943
    964             case 0xfa:
    965                 dsp_set_data(pThis, 0);
     944            case 0xfa:              /* ??? */
     945                sb16DspSeData(pThis, 0);
    966946                goto warn;
    967947
    968             case 0xfc:              /* FIXME */
    969                 dsp_set_data(pThis, 0);
     948            case 0xfc:              /* ??? */
     949                sb16DspSeData(pThis, 0);
    970950                goto warn;
    971951
    972952            default:
    973                 LogFlowFunc(("Unrecognized command %#x\n", cmd));
     953                LogFunc(("Unrecognized DSP command %#x, ignored\n", cmd));
    974954                break;
    975955        }
    976956    }
    977 
    978     if (!pThis->dsp_in_needed_bytes)
    979         LogFlow(("\n"));
    980957
    981958exit:
     
    989966
    990967warn:
    991     LogFlowFunc(("warning: command %#x,%d is not truly understood yet\n", cmd, pThis->dsp_in_needed_bytes));
     968    LogFunc(("warning: command %#x,%d is not truly understood yet\n", cmd, pThis->dsp_in_needed_bytes));
    992969    goto exit;
    993970}
    994971
    995 DECLINLINE(uint16_t) dsp_get_lohi(PSB16STATE pThis)
    996 {
    997     const uint8_t hi = dsp_get_data(pThis);
    998     const uint8_t lo = dsp_get_data(pThis);
     972DECLINLINE(uint16_t) sb16DspGetLoHi(PSB16STATE pThis)
     973{
     974    const uint8_t hi = sb16DspGetData(pThis);
     975    const uint8_t lo = sb16DspGetData(pThis);
    999976    return RT_MAKE_U16(lo, hi);
    1000977}
    1001978
    1002 DECLINLINE(uint16_t) dsp_get_hilo(PSB16STATE pThis)
    1003 {
    1004     const uint8_t lo = dsp_get_data(pThis);
    1005     const uint8_t hi = dsp_get_data(pThis);
     979DECLINLINE(uint16_t) sb16DspGetHiLo(PSB16STATE pThis)
     980{
     981    const uint8_t lo = sb16DspGetData(pThis);
     982    const uint8_t hi = sb16DspGetData(pThis);
    1006983    return RT_MAKE_U16(lo, hi);
    1007984}
    1008985
    1009 static void dsp_cmd_complete(PPDMDEVINS pDevIns, PSB16STATE pThis)
     986static void sb16DspCmdComplete(PPDMDEVINS pDevIns, PSB16STATE pThis)
    1010987{
    1011988    LogFlowFunc(("Command %#x, in_index %d, needed_bytes %d\n", pThis->cmd, pThis->dsp_in_idx, pThis->dsp_in_needed_bytes));
     
    1017994    if (pThis->cmd > 0xaf && pThis->cmd < 0xd0)
    1018995    {
    1019         v2 = dsp_get_data(pThis);
    1020         v1 = dsp_get_data(pThis);
    1021         v0 = dsp_get_data(pThis);
     996        v2 = sb16DspGetData(pThis);
     997        v1 = sb16DspGetData(pThis);
     998        v0 = sb16DspGetData(pThis);
    1022999
    10231000        if (pThis->cmd & 8)
     
    10261003        {
    10271004            LogFlowFunc(("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", pThis->cmd, v0, v1, v2));
    1028             dma_cmd(pDevIns, pThis, pThis->cmd, v0, v1 + (v2 << 8));
     1005            sb16DmaCmd(pDevIns, pThis, pStream, pThis->cmd, v0, v1 + (v2 << 8));
    10291006        }
    10301007    }
     
    10351012            case 0x04:
    10361013            {
    1037                 pThis->csp_mode = dsp_get_data(pThis);
     1014                pThis->csp_mode = sb16DspGetData(pThis);
    10381015                pThis->csp_reg83r = 0;
    10391016                pThis->csp_reg83w = 0;
     
    10441021            case 0x05:
    10451022            {
    1046                 pThis->csp_param = dsp_get_data(pThis);
    1047                 pThis->csp_value = dsp_get_data(pThis);
     1023                pThis->csp_param = sb16DspGetData(pThis);
     1024                pThis->csp_value = sb16DspGetData(pThis);
    10481025                LogFlowFunc(("CSP command 0x05: param=%#x value=%#x\n", pThis->csp_param, pThis->csp_value));
    10491026                break;
     
    10521029            case 0x0e:
    10531030            {
    1054                 v0 = dsp_get_data(pThis);
    1055                 v1 = dsp_get_data(pThis);
     1031                v0 = sb16DspGetData(pThis);
     1032                v1 = sb16DspGetData(pThis);
    10561033                LogFlowFunc(("write CSP register %d <- %#x\n", v1, v0));
    10571034                if (v1 == 0x83)
     
    10681045            case 0x0f:
    10691046            {
    1070                 v0 = dsp_get_data(pThis);
     1047                v0 = sb16DspGetData(pThis);
    10711048                LogFlowFunc(("read CSP register %#x -> %#x, mode=%#x\n", v0, pThis->csp_regs[v0], pThis->csp_mode));
    10721049                if (v0 == 0x83)
    10731050                {
    10741051                    LogFlowFunc(("0x83[%d] -> %#x\n", pThis->csp_reg83w, pThis->csp_reg83[pThis->csp_reg83w % 4]));
    1075                     dsp_set_data(pThis, pThis->csp_reg83[pThis->csp_reg83w % 4]);
     1052                    sb16DspSeData(pThis, pThis->csp_reg83[pThis->csp_reg83w % 4]);
    10761053                    pThis->csp_reg83w += 1;
    10771054                }
    10781055                else
    1079                     dsp_set_data(pThis, pThis->csp_regs[v0]);
     1056                    sb16DspSeData(pThis, pThis->csp_regs[v0]);
    10801057                break;
    10811058            }
    10821059
    10831060            case 0x10:
    1084                 v0 = dsp_get_data(pThis);
     1061                v0 = sb16DspGetData(pThis);
    10851062                LogFlowFunc(("cmd 0x10 d0=%#x\n", v0));
    10861063                break;
    10871064
    10881065            case 0x14:
    1089                 dma_cmd8(pDevIns, pThis, 0, dsp_get_lohi(pThis) + 1);
     1066                sb16DmaCmd8(pDevIns, pThis, pStream, 0, sb16DspGetLoHi(pThis) + 1);
    10901067                break;
    10911068
     
    10951072
    10961073            case 0x40: /* Sets the timer constant; SB16 is able to use sample rates via 0x41 instead. */
    1097                 pThis->time_const = dsp_get_data(pThis);
    1098                 LogFlowFunc(("set time const %d\n", pThis->time_const));
     1074                pStream->time_const = sb16DspGetData(pThis);
     1075                LogFlowFunc(("set time const %d\n", pStream->time_const));
    10991076                break;
    11001077
     
    11071084            case 0x41: /* Sets the output rate (in Hz). */
    11081085            {
    1109                 pThis->freq = dsp_get_hilo(pThis);
    1110                 LogFlowFunc(("set freq %d\n", pThis->freq));
     1086                pStream->Cfg.Props.uHz = sb16DspGetHiLo(pThis);
     1087                LogFlowFunc(("set freq to %RU16Hz\n", pStream->Cfg.Props.uHz));
    11111088                break;
    11121089            }
     
    11141091            case 0x48:
    11151092            {
    1116                 pThis->block_size = dsp_get_lohi(pThis) + 1;
    1117                 LogFlowFunc(("set dma block len %d\n", pThis->block_size));
     1093                pStream->cbDmaBlockSize = sb16DspGetLoHi(pThis) + 1;
     1094                LogFlowFunc(("set dma block len %d\n", pStream->cbDmaBlockSize));
    11181095                break;
    11191096            }
     
    11311108            case 0x80: /* Sets the IRQ. */
    11321109            {
    1133                 sb16StreamTransferScheduleNext(pThis, pStream, dsp_get_lohi(pThis) + 1);
     1110                sb16StreamTransferScheduleNext(pThis, pStream, sb16DspGetLoHi(pThis) + 1);
    11341111                break;
    11351112            }
     
    11371114            case 0xe0:
    11381115            {
    1139                 v0 = dsp_get_data(pThis);
     1116                v0 = sb16DspGetData(pThis);
    11401117                pThis->dsp_out_data_len = 0;
    11411118                LogFlowFunc(("E0=%#x\n", v0));
    1142                 dsp_set_data(pThis, ~v0);
     1119                sb16DspSeData(pThis, ~v0);
    11431120                break;
    11441121            }
     
    11461123            case 0xe2:
    11471124            {
    1148                 v0 = dsp_get_data(pThis);
     1125                v0 = sb16DspGetData(pThis);
    11491126                LogFlowFunc(("E2=%#x\n", v0));
    11501127                break;
     
    11521129
    11531130            case 0xe4:
    1154                 pThis->test_reg = dsp_get_data(pThis);
     1131                pThis->test_reg = sb16DspGetData(pThis);
    11551132                break;
    11561133
    11571134            case 0xf9:
    1158                 v0 = dsp_get_data(pThis);
     1135                v0 = sb16DspGetData(pThis);
    11591136                switch (v0)
    11601137                {
    11611138                    case 0x0e:
    1162                         dsp_set_data(pThis, 0xff);
     1139                        sb16DspSeData(pThis, 0xff);
    11631140                        break;
    11641141
    11651142                    case 0x0f:
    1166                         dsp_set_data(pThis, 0x07);
     1143                        sb16DspSeData(pThis, 0x07);
    11671144                        break;
    11681145
    11691146                    case 0x37:
    1170                         dsp_set_data(pThis, 0x38);
     1147                        sb16DspSeData(pThis, 0x38);
    11711148                        break;
    11721149
    11731150                    default:
    1174                         dsp_set_data(pThis, 0x00);
     1151                        sb16DspSeData(pThis, 0x00);
    11751152                        break;
    11761153                }
     
    11871164}
    11881165
    1189 static void sb16CmdResetLegacy(PSB16STATE pThis)
     1166static void sb16DspCmdResetLegacy(PSB16STATE pThis)
    11901167{
    11911168    LogFlowFuncEnter();
    11921169
    1193     pThis->freq       = 11025;
    1194     pThis->fmt_signed = 0;
    1195     pThis->fmt_bits   = 8;
    1196     pThis->fmt_stereo = 0;
     1170    /* Disable speaker(s). */
     1171    sb16SpeakerControl(pThis, false /* fOn */);
    11971172
    11981173    /*
     
    12001175     */
    12011176    for (unsigned i = 0; i < SB16_MAX_STREAMS; i++)
    1202     {
    1203         sb16StreamEnable(pThis, &pThis->aStreams[i], false /* fEnable */, false /* fForce */);
    12041177        sb16StreamReset(pThis, &pThis->aStreams[i]);
    1205     }
    1206 }
    1207 
    1208 static void sb16CmdReset(PPDMDEVINS pDevIns, PSB16STATE pThis)
    1209 {
    1210     PDMDevHlpISASetIrq(pDevIns, pThis->irq, 0);
    1211     if (pThis->dma_auto)
    1212     {
    1213         PDMDevHlpISASetIrq(pDevIns, pThis->irq, 1);
    1214         PDMDevHlpISASetIrq(pDevIns, pThis->irq, 0);
    1215     }
    1216 
     1178}
     1179
     1180static void sb16DspCmdReset(PSB16STATE pThis)
     1181{
    12171182    pThis->mixer_regs[0x82] = 0;
    1218     pThis->dma_auto = 0;
    12191183    pThis->dsp_in_idx = 0;
    12201184    pThis->dsp_out_data_len = 0;
    1221     pThis->left_till_irq = 0;
    12221185    pThis->dsp_in_needed_bytes = 0;
    1223     pThis->block_size = -1;
    12241186    pThis->nzero = 0;
    12251187    pThis->highspeed = 0;
     
    12271189    pThis->cmd = -1;
    12281190
    1229     dsp_set_data(pThis, 0xaa);
    1230     sb16SpeakerControl(pThis, 0);
    1231 
    1232     sb16Control(pDevIns, pThis, 0);
    1233     sb16CmdResetLegacy(pThis);
     1191    sb16DspSeData(pThis, 0xaa);
     1192
     1193    sb16DspCmdResetLegacy(pThis);
    12341194}
    12351195
     
    12411201    PSB16STATE pThis = PDMDEVINS_2_DATA(pDevIns, PSB16STATE);
    12421202    RT_NOREF(pvUser, cb);
     1203
     1204    /** @todo Figure out how we can distinguish between streams. DSP port #, e.g. 0x220? */
     1205    PSB16STREAM pStream = &pThis->aStreams[SB16_IDX_OUT];
    12431206
    12441207    LogFlowFunc(("write %#x <- %#x\n", offPort, u32));
     
    12551218                        {
    12561219                            pThis->highspeed = 0;
    1257                             PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
    1258                             sb16Control(pDevIns, pThis, 0);
     1220                            PDMDevHlpISASetIrq(pThis->pDevInsR3, pStream->HwCfgRuntime.uIrq, 0);
     1221                            sb16StreamControl(pDevIns, pThis, pStream, false /* fRun */);
    12591222                        }
    12601223                        else
    1261                             sb16CmdReset(pDevIns, pThis);
     1224                            sb16DspCmdReset(pThis);
    12621225                    }
    12631226                    pThis->v2x6 = 0;
     
    12751238
    12761239                case 0xb8:              /* Panic */
    1277                     sb16CmdReset(pDevIns, pThis);
     1240                    sb16DspCmdReset(pThis);
    12781241                    break;
    12791242
    12801243                case 0x39:
    1281                     dsp_set_data(pThis, 0x38);
    1282                     sb16CmdReset(pDevIns, pThis);
     1244                    sb16DspSeData(pThis, 0x38);
     1245                    sb16DspCmdReset(pThis);
    12831246                    pThis->v2x6 = 0x39;
    12841247                    break;
     
    12971260            if (0 == pThis->dsp_in_needed_bytes)
    12981261            {
    1299                 sb16HandleCommand(pDevIns, pThis, u32);
    1300 #if 0
    1301                 if (0 == pThis->needed_bytes) {
    1302                     log_dsp (pThis);
    1303                 }
    1304 #endif
     1262                sb16DspCmdLookup(pDevIns, pThis, pStream, u32);
    13051263            }
    13061264            else
     
    13161274                    {
    13171275                        pThis->dsp_in_needed_bytes = 0;
    1318                         dsp_cmd_complete(pDevIns, pThis);
    1319 #if 0
    1320                         log_dsp (pThis);
    1321 #endif
     1276                        sb16DspCmdComplete(pDevIns, pThis);
    13221277                    }
    13231278                }
     
    13391294static DECLCALLBACK(VBOXSTRICTRC) sb16IoPortDspRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
    13401295{
     1296    RT_NOREF(pvUser, cb);
     1297
    13411298    PSB16STATE pThis = PDMDEVINS_2_DATA(pDevIns, PSB16STATE);
     1299
    13421300    uint32_t retval;
    13431301    int ack = 0;
    1344     RT_NOREF(pvUser, cb);
    1345 
     1302
     1303    /** @todo Figure out how we can distinguish between streams. */
     1304    PSB16STREAM pStream = &pThis->aStreams[SB16_IDX_OUT];
    13461305
    13471306    /** @todo reject non-byte access?
     
    13701329
    13711330        case 6:                     /* 0 can write */
    1372             retval = pThis->can_write ? 0 : 0x80;
     1331            retval = pStream->can_write ? 0 : 0x80;
    13731332            break;
    13741333
     
    13841343                ack = 1;
    13851344                pThis->mixer_regs[0x82] &= ~1;
    1386                 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
     1345                PDMDevHlpISASetIrq(pThis->pDevInsR3, pStream->HwCfgRuntime.uIrq, 0);
    13871346            }
    13881347            break;
     
    13941353                ack = 1;
    13951354                pThis->mixer_regs[0x82] &= ~2;
    1396                PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
     1355                PDMDevHlpISASetIrq(pThis->pDevInsR3, pStream->HwCfgRuntime.uIrq, 0);
    13971356            }
    13981357            break;
     
    15701529}
    15711530
    1572 static int mixer_write_indexb(PSB16STATE pThis, uint8_t val)
    1573 {
     1531static int sb16MixerWriteIndex(PSB16STATE pThis, PSB16STREAM pStream, uint8_t val)
     1532{
     1533    RT_NOREF(pStream);
    15741534    pThis->mixer_nreg = val;
    15751535    return VINF_SUCCESS;
     
    16211581
    16221582
    1623 static int mixer_write_datab(PSB16STATE pThis, uint8_t val)
     1583static int sb16MixerWriteData(PSB16STATE pThis, PSB16STREAM pStream, uint8_t val)
    16241584{
    16251585    bool        fUpdateMaster = false;
    16261586    bool        fUpdateStream = false;
    16271587
    1628     LogFlowFunc(("sb16IoPortMixerWrite [%#x] <- %#x\n", pThis->mixer_nreg, val));
     1588    LogFlowFunc(("[%#x] <- %#x\n", pThis->mixer_nreg, val));
    16291589
    16301590    switch (pThis->mixer_nreg)
     
    17061666        {
    17071667            int irq = irq_of_magic(val);
    1708             LogFlowFunc(("setting irq to %d (val=%#x)\n", irq, val));
     1668            LogRelMax2(64, ("SB16: Setting IRQ to %d\n", irq));
    17091669            if (irq > 0)
    1710                 pThis->irq = irq;
     1670                pStream->HwCfgRuntime.uIrq = irq;
    17111671            break;
    17121672        }
     
    17141674        case 0x81:
    17151675        {
    1716             int dma, hdma;
    1717 
    1718             dma = lsbindex (val & 0xf);
    1719             hdma = lsbindex (val & 0xf0);
    1720             if (dma != pThis->dma || hdma != pThis->hdma)
    1721                 LogFlow(("SB16: attempt to change DMA 8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
    1722                          dma, pThis->dma, hdma, pThis->hdma, val));
     1676            int dma  = lsbindex(val & 0xf);
     1677            int hdma = lsbindex(val & 0xf0);
     1678            if (    dma != pStream->HwCfgRuntime.uDmaChanLow
     1679                || hdma != pStream->HwCfgRuntime.uDmaChanHigh)
     1680            {
     1681                LogRelMax2(64, ("SB16: Attempt to change DMA 8bit %d(%d), 16bit %d(%d)\n",
     1682                                dma, pStream->HwCfgRuntime.uDmaChanLow, hdma, pStream->HwCfgRuntime.uDmaChanHigh));
     1683            }
    17231684#if 0
    1724             pThis->dma = dma;
    1725             pThis->hdma = hdma;
     1685            pStream->dma = dma;
     1686            pStream->hdma = hdma;
    17261687#endif
    17271688            break;
     
    17291690
    17301691        case 0x82:
    1731             LogFlowFunc(("attempt to write into IRQ status register (val=%#x)\n", val));
     1692            LogRelMax2(64, ("SB16: Attempt to write into IRQ status register to %#x\n", val));
    17321693            return VINF_SUCCESS;
    17331694
     
    17571718    PSB16STATE pThis = PDMDEVINS_2_DATA(pDevIns, PSB16STATE);
    17581719    RT_NOREF(pvUser);
     1720
     1721    /** @todo Figure out how we can distinguish between streams. */
     1722    PSB16STREAM pStream = &pThis->aStreams[SB16_IDX_OUT];
    17591723
    17601724    switch (cb)
     
    17641728            {
    17651729                case 0:
    1766                     mixer_write_indexb(pThis, u32);
     1730                    sb16MixerWriteIndex(pThis, pStream, u32);
    17671731                    break;
    17681732                case 1:
    1769                     mixer_write_datab(pThis, u32);
     1733                    sb16MixerWriteData(pThis, pStream, u32);
    17701734                    break;
    17711735                default:
     
    17741738            break;
    17751739        case 2:
    1776             mixer_write_indexb(pThis, u32 & 0xff);
    1777             mixer_write_datab(pThis, (u32 >> 8) & 0xff);
     1740            sb16MixerWriteIndex(pThis, pStream, u32 & 0xff);
     1741            sb16MixerWriteData(pThis, pStream, (u32 >> 8) & 0xff);
    17781742            break;
    17791743        default:
     
    18251789    int till, copy, free;
    18261790
    1827     if (pThis->block_size <= 0)
    1828     {
    1829         LogFlowFunc(("invalid block size=%d uChannel=%d off=%d cb=%d\n", pThis->block_size, uChannel, off, cb));
     1791    if (pStream->cbDmaBlockSize <= 0)
     1792    {
     1793        LogFlowFunc(("invalid block size=%d uChannel=%d off=%d cb=%d\n", pStream->cbDmaBlockSize, uChannel, off, cb));
    18301794        return off;
    18311795    }
    18321796
    1833     if (pThis->left_till_irq < 0)
    1834         pThis->left_till_irq = pThis->block_size;
     1797    if (pStream->cbDmaLeft < 0)
     1798        pStream->cbDmaLeft = pStream->cbDmaBlockSize;
    18351799
    18361800    free = cb;
    18371801
    18381802    copy = free;
    1839     till = pThis->left_till_irq;
     1803    till = pStream->cbDmaLeft;
    18401804
    18411805    Log4Func(("pos=%d %d, till=%d, len=%d\n", off, free, till, cb));
     
    18431807    if (copy >= till)
    18441808    {
    1845         if (0 == pThis->dma_auto)
     1809        if (0 == pStream->dma_auto)
    18461810        {
    18471811            copy = till;
     
    18491813        else
    18501814        {
    1851             if (copy >= till + pThis->block_size)
     1815            if (copy >= till + pStream->cbDmaBlockSize)
    18521816                copy = till; /* Make sure we won't skip IRQs. */
    18531817        }
     
    18621826    /** @todo Convert the rest to uin32_t / size_t. */
    18631827    off = (off + (int)written) % cb;
    1864     pThis->left_till_irq -= (int)written; /** @todo r=andy left_till_irq can be < 0. Correct? Revisit this. */
     1828    pStream->cbDmaLeft -= (int)written; /** @todo r=andy left_till_irq can be < 0. Correct? Revisit this. */
    18651829
    18661830    Log3Func(("pos %d/%d, free=%d, till=%d, copy=%d, written=%RU32, block_size=%d\n",
    1867               off, cb, free, pThis->left_till_irq, copy, copy, pThis->block_size));
    1868 
    1869     if (pThis->left_till_irq <= 0)
     1831              off, cb, free, pStream->cbDmaLeft, copy, copy, pStream->cbDmaBlockSize));
     1832
     1833    if (pStream->cbDmaLeft <= 0)
    18701834    {
    18711835        pThis->mixer_regs[0x82] |= (uChannel & 4) ? 2 : 1;
    18721836
    1873         PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
    1874 
    1875         if (0 == pThis->dma_auto) /** @todo r=andy BUGBUG Why do we first assert the IRQ if dma_auto is 0? Revisit this. */
     1837        PDMDevHlpISASetIrq(pThis->pDevInsR3, pStream->HwCfgRuntime.uIrq, 1);
     1838
     1839        if (0 == pStream->dma_auto) /** @todo r=andy BUGBUG Why do we first assert the IRQ if dma_auto is 0? Revisit this. */
    18761840        {
    1877             sb16Control(pDevIns, pThis, 0);
     1841            sb16StreamControl(pDevIns, pThis, pStream, false /* fRun */);
    18781842            sb16SpeakerControl(pThis, 0);
    18791843        }
    18801844    }
    18811845
    1882     while (pThis->left_till_irq <= 0)
    1883         pThis->left_till_irq += pThis->block_size;
     1846    while (pStream->cbDmaLeft <= 0)
     1847        pStream->cbDmaLeft += pStream->cbDmaBlockSize;
    18841848
    18851849    return off;
     
    18971861{
    18981862    PSB16STATE pThis = PDMDEVINS_2_DATA(pDevIns, PSB16STATE);
    1899     RT_NOREF(pvUser, hTimer);
     1863    RT_NOREF(hTimer, pThis);
     1864
     1865    PSB16STREAM pStream = (PSB16STREAM)pvUser;
     1866    AssertPtrReturnVoid(pStream);
    19001867
    19011868    LogFlowFuncEnter();
    19021869
    1903     pThis->can_write = 1;
    1904     PDMDevHlpISASetIrq(pDevIns, pThis->irq, 1);
     1870    pStream->can_write = 1;
     1871    PDMDevHlpISASetIrq(pDevIns, pStream->HwCfgRuntime.uIrq, 1);
    19051872}
    19061873
     
    19231890static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)
    19241891{
     1892    PSB16STATE pThis = PDMDEVINS_2_DATA(pDevIns, PSB16STATE);
     1893    STAM_PROFILE_START(&pThis->StatTimerIO, a);
     1894
    19251895    PSB16STREAM pStream = (PSB16STREAM)pvUser;
    19261896    AssertPtrReturnVoid(pStream);
    1927 
    1928     PSB16STATE pThis = PDMDEVINS_2_DATA(pDevIns, PSB16STATE);
    1929     STAM_PROFILE_START(&pThis->StatTimerIO, a);
    19301897    AssertReturnVoid(hTimer == pStream->hTimerIO);
    19311898
     
    24002367    LogFlowFuncEnter();
    24012368
     2369    PDMDevHlpISASetIrq(pThis->pDevInsR3, pStream->HwCfgRuntime.uIrq, 0);
     2370    if (pStream->dma_auto)
     2371    {
     2372        PDMDevHlpISASetIrq(pThis->pDevInsR3, pStream->HwCfgRuntime.uIrq, 1);
     2373        PDMDevHlpISASetIrq(pThis->pDevInsR3, pStream->HwCfgRuntime.uIrq, 0);
     2374
     2375        pStream->dma_auto = 0;
     2376    }
     2377
     2378    sb16StreamControl(pThis->pDevInsR3, pThis, pStream, false /* fRun */);
     2379    sb16StreamEnable(pThis, pStream, false /* fEnable */, false /* fForce */);
     2380
    24022381    switch (pStream->uIdx)
    24032382    {
     
    24082387            pStream->Cfg.enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
    24092388
    2410             PDMAudioPropsInit(&pStream->Cfg.Props, 1 /* 8-bit */, false /* fSigned */, 1 /* Mono */, pThis->freq);
     2389            PDMAudioPropsInit(&pStream->Cfg.Props, 1 /* 8-bit */, false /* fSigned */, 1 /* Mono */, 11025 /* uHz */);
    24112390            RTStrCopy(pStream->Cfg.szName, sizeof(pStream->Cfg.szName), "Output");
    24122391
     
    24182397            break;
    24192398    }
     2399
     2400    pStream->cbDmaLeft      = 0;
     2401    pStream->cbDmaBlockSize = 0;
     2402    pStream->can_write      = 1; /** @ŧodo r=andy BUGBUG Figure out why we (still) need this. */
    24202403
    24212404    /** @todo Also reset corresponding DSP values here? */
     
    24362419    LogFlowFuncEnter();
    24372420
    2438     PDMAUDIOSTREAMCFG Cfg;
    2439     RT_ZERO(Cfg);
    2440 
    2441     /** @todo Implement mixer sink selection (and it's in/out + destination mapping) here once we add more streams. */
    2442     PDMAudioPropsInit(&Cfg.Props, pThis->fmt_bits / 8, pThis->fmt_signed != 0, 1 << pThis->fmt_stereo, pThis->freq);
    2443 
    2444     /* Bail out early if the PCM properties did not change. */
    2445     if (PDMAudioPropsAreEqual(&Cfg.Props, &pStream->Cfg.Props))
    2446         return VINF_SUCCESS;
     2421    PDMAudioPropsInit(&pStream->Cfg.Props,
     2422                      pStream->Cfg.Props.cbSampleX,
     2423                      pStream->Cfg.Props.fSigned,
     2424                      pStream->Cfg.Props.cChannelsX,
     2425                      pStream->Cfg.Props.uHz);
     2426
     2427    AssertReturn(PDMAudioPropsAreValid(&pStream->Cfg.Props), VERR_INVALID_PARAMETER);
    24472428
    24482429    PDMAUDIODSTSRCUNION dstSrc;
     
    24532434        case SB16_IDX_OUT:
    24542435        {
    2455             Cfg.enmDir      = PDMAUDIODIR_OUT;
    2456             Cfg.u.enmDst    = PDMAUDIOPLAYBACKDST_FRONT;
    2457             Cfg.enmLayout   = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
    2458 
    2459             RTStrCopy(Cfg.szName, sizeof(Cfg.szName), "Output");
     2436            pStream->Cfg.enmDir      = PDMAUDIODIR_OUT;
     2437            pStream->Cfg.u.enmDst    = PDMAUDIOPLAYBACKDST_FRONT;
     2438            pStream->Cfg.enmLayout   = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
     2439
     2440            RTStrCopy(pStream->Cfg.szName, sizeof(pStream->Cfg.szName), "Output");
    24602441
    24612442            dstSrc.enmDst = PDMAUDIOPLAYBACKDST_FRONT;
     
    24692450    }
    24702451
    2471     LogRel2(("SB16: (Re-)Opening stream '%s' (%RU32Hz, %RU8 channels, %s%RU8)\n", Cfg.szName, Cfg.Props.uHz,
    2472              PDMAudioPropsChannels(&Cfg.Props), Cfg.Props.fSigned ? "S" : "U",  PDMAudioPropsSampleBits(&Cfg.Props)));
    2473 
    2474     int rc = PDMAudioStrmCfgCopy(&pStream->Cfg, &Cfg);
    2475     if (RT_FAILURE(rc))
    2476         return rc;
     2452    LogRel2(("SB16: (Re-)Opening stream '%s' (%RU32Hz, %RU8 channels, %s%RU8)\n", pStream->Cfg.szName, pStream->Cfg.Props.uHz,
     2453             PDMAudioPropsChannels(&pStream->Cfg.Props), pStream->Cfg.Props.fSigned ? "S" : "U",
     2454             PDMAudioPropsSampleBits(&pStream->Cfg.Props)));
    24772455
    24782456    /* (Re-)create the stream's internal ring buffer. */
     
    24832461    }
    24842462
    2485     const uint32_t cbCircBuf = PDMAudioPropsMilliToBytes(&pStream->Cfg.Props, 2 * 10 /* ms */);
    2486 
    2487     rc = RTCircBufCreate(&pStream->State.pCircBuf, cbCircBuf);
     2463    const uint32_t cbCircBuf
     2464        = PDMAudioPropsMilliToBytes(&pStream->Cfg.Props, (RT_MS_1SEC / pStream->uTimerHz) * 2 /* Use double buffering here */);
     2465
     2466    int rc = RTCircBufCreate(&pStream->State.pCircBuf, cbCircBuf);
    24882467    AssertRCReturn(rc, rc);
    24892468
    24902469    /* Set scheduling hint (if available). */
    24912470    if (pStream->cTicksTimerIOInterval)
    2492         pStream->Cfg.Device.cMsSchedulingHint = 1000 /* ms */
    2493                                               / (  PDMDevHlpTimerGetFreq(pDevIns, pStream->hTimerIO)
    2494                                               / RT_MIN(pStream->cTicksTimerIOInterval, 1));
     2471        pStream->Cfg.Device.cMsSchedulingHint = RT_MS_1SEC / pStream->uTimerHz;
    24952472
    24962473    PAUDMIXSINK pMixerSink = sb16StreamIndexToSink(pThis, pStream->uIdx);
     
    25452522    RT_NOREF(pStream);
    25462523
    2547 #if 0
    2548     uint32_t const freq     = pThis->freq > 0 ? pThis->freq : 11025;
    2549     uint32_t const bytes    = cSamples << pThis->fmt_stereo << (pThis->fmt_bits == 16 ? 1 : 0);
    2550     uint64_t const uTimerHz = PDMDevHlpTimerGetFreq(pThis->pDevInsR3, pThis->hTimerIRQ);
    2551     uint64_t const cTicks   = (bytes * uTimerHz) / freq;
    2552 #endif
    2553 
    25542524    uint64_t const uTimerHz = PDMDevHlpTimerGetFreq(pThis->pDevInsR3, pThis->hTimerIRQ);
    25552525
     
    25622532    {
    25632533        LogFlowFunc(("IRQ\n"));
    2564         PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
     2534        PDMDevHlpISASetIrq(pThis->pDevInsR3, pStream->HwCfgRuntime.uIrq, 1);
    25652535    }
    25662536    else
     
    26292599static DECLCALLBACK(int) sb16LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
    26302600{
     2601    RT_NOREF(uPass);
     2602
    26312603    PSB16STATE    pThis = PDMDEVINS_2_DATA(pDevIns, PSB16STATE);
    26322604    PCPDMDEVHLPR3 pHlp  = pDevIns->pHlpR3;
    2633     RT_NOREF(uPass);
    2634 
    2635     pHlp->pfnSSMPutS32(pSSM, pThis->irqCfg);
    2636     pHlp->pfnSSMPutS32(pSSM, pThis->dmaCfg);
    2637     pHlp->pfnSSMPutS32(pSSM, pThis->hdmaCfg);
    2638     pHlp->pfnSSMPutS32(pSSM, pThis->portCfg);
    2639     pHlp->pfnSSMPutS32(pSSM, pThis->verCfg);
     2605
     2606    /** Currently the saved state only contains the one-and-only output stream. */
     2607    PSB16STREAM pStream = &pThis->aStreams[SB16_IDX_OUT];
     2608
     2609    pHlp->pfnSSMPutS32(pSSM, pStream->HwCfgDefault.uIrq);
     2610    pHlp->pfnSSMPutS32(pSSM, pStream->HwCfgDefault.uDmaChanLow);
     2611    pHlp->pfnSSMPutS32(pSSM, pStream->HwCfgDefault.uDmaChanHigh);
     2612    pHlp->pfnSSMPutS32(pSSM, pStream->HwCfgDefault.uPort);
     2613    pHlp->pfnSSMPutS32(pSSM, pStream->HwCfgDefault.uVer);
    26402614    return VINF_SSM_DONT_CALL_AGAIN;
    26412615}
     
    26462620static int sb16Save(PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, PSB16STATE pThis)
    26472621{
    2648     pHlp->pfnSSMPutS32(pSSM, pThis->irq);
    2649     pHlp->pfnSSMPutS32(pSSM, pThis->dma);
    2650     pHlp->pfnSSMPutS32(pSSM, pThis->hdma);
    2651     pHlp->pfnSSMPutS32(pSSM, pThis->port);
    2652     pHlp->pfnSSMPutS32(pSSM, pThis->ver);
     2622    /** Currently the saved state only contains the one-and-only output stream. */
     2623    PSB16STREAM pStream = &pThis->aStreams[SB16_IDX_OUT];
     2624
     2625    pHlp->pfnSSMPutS32(pSSM, pStream->HwCfgRuntime.uIrq);
     2626    pHlp->pfnSSMPutS32(pSSM, pStream->HwCfgRuntime.uDmaChanLow);
     2627    pHlp->pfnSSMPutS32(pSSM, pStream->HwCfgRuntime.uDmaChanHigh);
     2628    pHlp->pfnSSMPutS32(pSSM, pStream->HwCfgRuntime.uPort);
     2629    pHlp->pfnSSMPutS32(pSSM, pStream->HwCfgRuntime.uVer);
    26532630    pHlp->pfnSSMPutS32(pSSM, pThis->dsp_in_idx);
    26542631    pHlp->pfnSSMPutS32(pSSM, pThis->dsp_out_data_len);
    2655     pHlp->pfnSSMPutS32(pSSM, pThis->fmt_stereo);
    2656     pHlp->pfnSSMPutS32(pSSM, pThis->fmt_signed);
    2657     pHlp->pfnSSMPutS32(pSSM, pThis->fmt_bits);
    2658 
    2659     pHlp->pfnSSMPutU32(pSSM, pThis->fmt);
    2660 
    2661     pHlp->pfnSSMPutS32(pSSM, pThis->dma_auto);
    2662     pHlp->pfnSSMPutS32(pSSM, pThis->block_size);
    2663     pHlp->pfnSSMPutS32(pSSM, pThis->fifo);
    2664     pHlp->pfnSSMPutS32(pSSM, pThis->freq);
    2665     pHlp->pfnSSMPutS32(pSSM, pThis->time_const);
    2666     pHlp->pfnSSMPutS32(pSSM, pThis->speaker);
     2632
     2633    /** Currently the saved state only contains the one-and-only output stream. */
     2634    pHlp->pfnSSMPutS32(pSSM, pStream->Cfg.Props.cChannelsX >= 2 ? 1 : 0);
     2635    pHlp->pfnSSMPutS32(pSSM, pStream->Cfg.Props.fSigned         ? 1 : 0);
     2636    pHlp->pfnSSMPutS32(pSSM, pStream->Cfg.Props.cbSampleX * 8 /* Convert bytes to bits */);
     2637    pHlp->pfnSSMPutU32(pSSM, 0); /* Legacy; was PDMAUDIOFMT, unused now. */
     2638
     2639    pHlp->pfnSSMPutS32(pSSM, pStream->dma_auto);
     2640    pHlp->pfnSSMPutS32(pSSM, pStream->cbDmaBlockSize);
     2641    pHlp->pfnSSMPutS32(pSSM, pStream->fifo);
     2642    pHlp->pfnSSMPutS32(pSSM, pStream->Cfg.Props.uHz);
     2643    pHlp->pfnSSMPutS32(pSSM, pStream->time_const);
     2644    pHlp->pfnSSMPutS32(pSSM, 0); /* Legacy; was speaker control (on/off) for output stream. */
    26672645    pHlp->pfnSSMPutS32(pSSM, pThis->dsp_in_needed_bytes);
    26682646    pHlp->pfnSSMPutS32(pSSM, pThis->cmd);
    2669     pHlp->pfnSSMPutS32(pSSM, pThis->use_hdma);
     2647    pHlp->pfnSSMPutS32(pSSM, pStream->fDmaUseHigh);
    26702648    pHlp->pfnSSMPutS32(pSSM, pThis->highspeed);
    2671     pHlp->pfnSSMPutS32(pSSM, pThis->can_write);
     2649    pHlp->pfnSSMPutS32(pSSM, pStream->can_write);
    26722650    pHlp->pfnSSMPutS32(pSSM, pThis->v2x6);
    26732651
     
    26882666
    26892667    pHlp->pfnSSMPutS32(pSSM, pThis->nzero);
    2690     pHlp->pfnSSMPutS32(pSSM, pThis->left_till_irq);
    2691     pHlp->pfnSSMPutS32(pSSM, pThis->dma_running);
    2692     pHlp->pfnSSMPutS32(pSSM, pThis->bytes_per_second);
    2693     pHlp->pfnSSMPutS32(pSSM, pThis->align);
     2668    pHlp->pfnSSMPutS32(pSSM, pStream->cbDmaLeft);
     2669    pHlp->pfnSSMPutS32(pSSM, pStream->State.fEnabled ? 1 : 0);
     2670    /* The stream's bitrate. Needed for backwards (legacy) compatibility. */
     2671    pHlp->pfnSSMPutS32(pSSM, AudioHlpCalcBitrate(pThis->aStreams[SB16_IDX_OUT].Cfg.Props.cbSampleX * 8,
     2672                                                 pThis->aStreams[SB16_IDX_OUT].Cfg.Props.uHz,
     2673                                                 pThis->aStreams[SB16_IDX_OUT].Cfg.Props.cChannelsX));
     2674    /* Block size alignment, superfluous and thus not saved anymore. Needed for backwards (legacy) compatibility. */
     2675    pHlp->pfnSSMPutS32(pSSM, 0);
    26942676
    26952677    pHlp->pfnSSMPutS32(pSSM, pThis->mixer_nreg);
     
    27162698    PCPDMDEVHLPR3 pHlp  = pDevIns->pHlpR3;
    27172699
    2718     pHlp->pfnSSMGetS32(pSSM, &pThis->irq);
    2719     pHlp->pfnSSMGetS32(pSSM, &pThis->dma);
    2720     pHlp->pfnSSMGetS32(pSSM, &pThis->hdma);
    2721     pHlp->pfnSSMGetS32(pSSM, &pThis->port);
    2722     pHlp->pfnSSMGetS32(pSSM, &pThis->ver);
     2700    /** Currently the saved state only contains the one-and-only output stream. */
     2701    PSB16STREAM pStream = &pThis->aStreams[SB16_IDX_OUT];
     2702
     2703    int32_t s32Tmp;
     2704    pHlp->pfnSSMGetS32(pSSM, &s32Tmp);
     2705    pStream->HwCfgRuntime.uIrq = s32Tmp;
     2706    pHlp->pfnSSMGetS32(pSSM, &s32Tmp);
     2707    pStream->HwCfgRuntime.uDmaChanLow = s32Tmp;
     2708    pHlp->pfnSSMGetS32(pSSM, &s32Tmp);
     2709    pStream->HwCfgRuntime.uDmaChanHigh = s32Tmp;
     2710    pHlp->pfnSSMGetS32(pSSM, &s32Tmp); /* Port */
     2711    pStream->HwCfgRuntime.uPort = s32Tmp;
     2712    pHlp->pfnSSMGetS32(pSSM, &s32Tmp); /* Ver */
     2713    pStream->HwCfgRuntime.uVer  = s32Tmp;
    27232714    pHlp->pfnSSMGetS32(pSSM, &pThis->dsp_in_idx);
    27242715    pHlp->pfnSSMGetS32(pSSM, &pThis->dsp_out_data_len);
    2725     pHlp->pfnSSMGetS32(pSSM, &pThis->fmt_stereo);
    2726     pHlp->pfnSSMGetS32(pSSM, &pThis->fmt_signed);
    2727     pHlp->pfnSSMGetS32(pSSM, &pThis->fmt_bits);
    2728 
    2729     PDMDEVHLP_SSM_GET_ENUM32_RET(pHlp, pSSM, pThis->fmt, PDMAUDIOFMT);
    2730 
    2731     pHlp->pfnSSMGetS32(pSSM, &pThis->dma_auto);
    2732     pHlp->pfnSSMGetS32(pSSM, &pThis->block_size);
    2733     pHlp->pfnSSMGetS32(pSSM, &pThis->fifo);
    2734     pHlp->pfnSSMGetS32(pSSM, &pThis->freq);
    2735     pHlp->pfnSSMGetS32(pSSM, &pThis->time_const);
    2736     pHlp->pfnSSMGetS32(pSSM, &pThis->speaker);
     2716    pHlp->pfnSSMGetS32(pSSM, &s32Tmp); /* Channels */
     2717    pStream->Cfg.Props.cChannelsX = (uint8_t)s32Tmp;
     2718    pHlp->pfnSSMGetS32(pSSM, &s32Tmp); /* Signed */
     2719    pStream->Cfg.Props.fSigned    = s32Tmp == 0 ? false : true;
     2720    pHlp->pfnSSMGetS32(pSSM, &s32Tmp);
     2721    pStream->Cfg.Props.cbSampleX  = s32Tmp / 8; /* Convert bits to bytes. */
     2722    pHlp->pfnSSMSkip  (pSSM, sizeof(int32_t));  /* Legacy; was PDMAUDIOFMT, unused now. */
     2723    pHlp->pfnSSMGetS32(pSSM, &pStream->dma_auto);
     2724    pHlp->pfnSSMGetS32(pSSM, &pThis->aStreams[SB16_IDX_OUT].cbDmaBlockSize);
     2725    pHlp->pfnSSMGetS32(pSSM, &pStream->fifo);
     2726    pHlp->pfnSSMGetS32(pSSM, &s32Tmp); pStream->Cfg.Props.uHz = s32Tmp;
     2727    pHlp->pfnSSMGetS32(pSSM, &pStream->time_const);
     2728    pHlp->pfnSSMSkip  (pSSM, sizeof(int32_t));  /* Legacy; was speaker (on / off) for output stream. */
    27372729    pHlp->pfnSSMGetS32(pSSM, &pThis->dsp_in_needed_bytes);
    27382730    pHlp->pfnSSMGetS32(pSSM, &pThis->cmd);
    2739     pHlp->pfnSSMGetS32(pSSM, &pThis->use_hdma);
     2731    pHlp->pfnSSMGetS32(pSSM, &pStream->fDmaUseHigh);
    27402732    pHlp->pfnSSMGetS32(pSSM, &pThis->highspeed);
    2741     pHlp->pfnSSMGetS32(pSSM, &pThis->can_write);
     2733    pHlp->pfnSSMGetS32(pSSM, &pStream->can_write);
    27422734    pHlp->pfnSSMGetS32(pSSM, &pThis->v2x6);
    27432735
     
    27582750
    27592751    pHlp->pfnSSMGetS32(pSSM, &pThis->nzero);
    2760     pHlp->pfnSSMGetS32(pSSM, &pThis->left_till_irq);
    2761     pHlp->pfnSSMGetS32(pSSM, &pThis->dma_running);
    2762     pHlp->pfnSSMGetS32(pSSM, &pThis->bytes_per_second);
    2763     pHlp->pfnSSMGetS32(pSSM, &pThis->align);
     2752    pHlp->pfnSSMGetS32(pSSM, &pStream->cbDmaLeft);
     2753    pHlp->pfnSSMGetS32(pSSM, &s32Tmp);
     2754    pStream->State.fEnabled = s32Tmp == 0 ? false: true;
     2755    pHlp->pfnSSMSkip  (pSSM, sizeof(int32_t)); /* Legacy; was the output stream's current bitrate (in bytes). */
     2756    pHlp->pfnSSMSkip  (pSSM, sizeof(int32_t)); /* Legacy; was the output stream's DMA block alignment. */
    27642757
    27652758    int32_t mixer_nreg = 0;
     
    27702763    AssertRCReturn(rc, rc);
    27712764
    2772     if (pThis->dma_running)
    2773     {
    2774         sb16Control(pDevIns, pThis, 1);
    2775         sb16SpeakerControl(pThis, pThis->speaker);
    2776     }
     2765    if (pStream->State.fEnabled)
     2766        sb16StreamControl(pDevIns, pThis, pStream, true /* fRun */);
    27772767
    27782768    /* Update the master (mixer) and PCM out volumes. */
     
    27962786    if (uVersion > SB16_SAVE_STATE_VERSION_VBOX_30)
    27972787    {
     2788        /** Currently the saved state only contains the one-and-only output stream. */
     2789        PSB16STREAM pStream = &pThis->aStreams[SB16_IDX_OUT];
     2790
    27982791        int32_t irq;
    27992792        pHlp->pfnSSMGetS32(pSSM, &irq);
     
    28082801        AssertRCReturn (rc, rc);
    28092802
    2810         if (   irq  != pThis->irqCfg
    2811             || dma  != pThis->dmaCfg
    2812             || hdma != pThis->hdmaCfg
    2813             || port != pThis->portCfg
    2814             || ver  != pThis->verCfg)
     2803        if (   irq  != pStream->HwCfgDefault.uIrq
     2804            || dma  != pStream->HwCfgDefault.uDmaChanLow
     2805            || hdma != pStream->HwCfgDefault.uDmaChanHigh
     2806            || port != pStream->HwCfgDefault.uPort
     2807            || ver  != pStream->HwCfgDefault.uVer)
    28152808        {
    28162809            return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS,
    28172810                                           N_("config changed: irq=%x/%x dma=%x/%x hdma=%x/%x port=%x/%x ver=%x/%x (saved/config)"),
    2818                                            irq,  pThis->irqCfg,
    2819                                            dma,  pThis->dmaCfg,
    2820                                            hdma, pThis->hdmaCfg,
    2821                                            port, pThis->portCfg,
    2822                                            ver,  pThis->verCfg);
     2811                                           irq,  pStream->HwCfgDefault.uIrq,
     2812                                           dma,  pStream->HwCfgDefault.uDmaChanLow,
     2813                                           hdma, pStream->HwCfgDefault.uDmaChanHigh,
     2814                                           port, pStream->HwCfgDefault.uPort,
     2815                                           ver,  pStream->HwCfgDefault.uVer);
    28232816        }
    28242817    }
     
    30173010    LogRel2(("SB16: Reset\n"));
    30183011
    3019     /* Bring back the device to initial state, and especially make
    3020      * sure there's no interrupt or DMA activity.
    3021      */
    3022     PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
    3023 
    30243012    pThis->mixer_regs[0x82] = 0;
    30253013    pThis->csp_regs[5]      = 1;
    30263014    pThis->csp_regs[9]      = 0xf8;
    30273015
    3028     pThis->dma_auto = 0;
    30293016    pThis->dsp_in_idx = 0;
    30303017    pThis->dsp_out_data_len = 0;
    3031     pThis->left_till_irq = 0;
    30323018    pThis->dsp_in_needed_bytes = 0;
    3033     pThis->block_size = -1;
    30343019    pThis->nzero = 0;
    30353020    pThis->highspeed = 0;
     
    30393024    sb16MixerReset(pThis);
    30403025    sb16SpeakerControl(pThis, 0);
    3041     sb16Control(pDevIns, pThis, 0);
    3042     sb16CmdResetLegacy(pThis);
     3026    sb16DspCmdResetLegacy(pThis);
    30433027}
    30443028
     
    31313115     * Validate and read config data.
    31323116     */
     3117    /* Note: For now we only support the one-and-only output stream. */
     3118    PSB16STREAM pStream = &pThis->aStreams[SB16_IDX_OUT];
     3119
    31333120    PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IRQ|DMA|DMA16|Port|Version|TimerHz|DebugEnabled|DebugPathOut", "");
    3134     int rc = pHlp->pfnCFGMQuerySIntDef(pCfg, "IRQ", &pThis->irq, 5);
     3121    int rc = pHlp->pfnCFGMQueryU8Def(pCfg, "IRQ", &pStream->HwCfgDefault.uIrq, 5);
    31353122    if (RT_FAILURE(rc))
    31363123        return PDMDEV_SET_ERROR(pDevIns, rc, N_("SB16 configuration error: Failed to get the \"IRQ\" value"));
    3137     pThis->irqCfg  = pThis->irq;
    3138 
    3139     rc = pHlp->pfnCFGMQuerySIntDef(pCfg, "DMA", &pThis->dma, 1);
     3124    pStream->HwCfgRuntime.uIrq  = pStream->HwCfgDefault.uIrq;
     3125
     3126    rc = pHlp->pfnCFGMQueryU8Def(pCfg, "DMA", &pStream->HwCfgDefault.uDmaChanLow, 1);
    31403127    if (RT_FAILURE(rc))
    31413128        return PDMDEV_SET_ERROR(pDevIns, rc, N_("SB16 configuration error: Failed to get the \"DMA\" value"));
    3142     pThis->dmaCfg  = pThis->dma;
    3143 
    3144     rc = pHlp->pfnCFGMQuerySIntDef(pCfg, "DMA16", &pThis->hdma, 5);
     3129    pStream->HwCfgRuntime.uDmaChanLow  = pStream->HwCfgDefault.uDmaChanLow;
     3130
     3131    rc = pHlp->pfnCFGMQueryU8Def(pCfg, "DMA16", &pStream->HwCfgDefault.uDmaChanHigh, 5);
    31453132    if (RT_FAILURE(rc))
    31463133        return PDMDEV_SET_ERROR(pDevIns, rc, N_("SB16 configuration error: Failed to get the \"DMA16\" value"));
    3147     pThis->hdmaCfg = pThis->hdma;
    3148 
    3149     RTIOPORT Port;
    3150     rc = pHlp->pfnCFGMQueryPortDef(pCfg, "Port", &Port, 0x220);
     3134    pStream->HwCfgRuntime.uDmaChanHigh = pStream->HwCfgDefault.uDmaChanHigh;
     3135
     3136    rc = pHlp->pfnCFGMQueryPortDef(pCfg, "Port", &pStream->HwCfgDefault.uPort, 0x220);
    31513137    if (RT_FAILURE(rc))
    31523138        return PDMDEV_SET_ERROR(pDevIns, rc, N_("SB16 configuration error: Failed to get the \"Port\" value"));
    3153     pThis->port    = Port;
    3154     pThis->portCfg = Port;
    3155 
    3156     uint16_t u16Version;
    3157     rc = pHlp->pfnCFGMQueryU16Def(pCfg, "Version", &u16Version, 0x0405);
     3139    pStream->HwCfgRuntime.uPort = pStream->HwCfgDefault.uPort;
     3140
     3141    rc = pHlp->pfnCFGMQueryU16Def(pCfg, "Version", &pStream->HwCfgDefault.uVer, 0x0405);
    31583142    if (RT_FAILURE(rc))
    31593143        return PDMDEV_SET_ERROR(pDevIns, rc, N_("SB16 configuration error: Failed to get the \"Version\" value"));
    3160     pThis->ver     = u16Version;
    3161     pThis->verCfg  = u16Version;
    3162 
    3163     uint16_t uTimerHz;
    3164     rc = pHlp->pfnCFGMQueryU16Def(pCfg, "TimerHz", &uTimerHz, 100 /* Hz */);
     3144    pStream->HwCfgRuntime.uVer = pStream->HwCfgDefault.uVer;
     3145
     3146    rc = pHlp->pfnCFGMQueryU16Def(pCfg, "TimerHz", &pStream->uTimerHz, SB16_TIMER_HZ_DEFAULT);
    31653147    if (RT_FAILURE(rc))
    3166         return PDMDEV_SET_ERROR(pDevIns, rc, N_("SB16 configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
    3167     if (uTimerHz == 0)
    3168         return PDMDEV_SET_ERROR(pDevIns, rc, N_("SB16 configuration error: TimerHz is zero"));
    3169     if (uTimerHz > 2048)
    3170         return PDMDEV_SET_ERROR(pDevIns, rc, N_("SB16 configuration error: Max TimerHz value is 2048."));
     3148        return PDMDEV_SET_ERROR(pDevIns, rc, N_("SB16 configuration error: failed to read Hertz rate as unsigned integer"));
     3149    if (pStream->uTimerHz == 0)
     3150        return PDMDEV_SET_ERROR(pDevIns, rc, N_("SB16 configuration error: Hertz rate is invalid"));
     3151    if (pStream->uTimerHz > 2048)
     3152        return PDMDEV_SET_ERROR(pDevIns, rc, N_("SB16 configuration error: Maximum Hertz rate is 2048"));
    31713153
    31723154    rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "DebugEnabled", &pThis->Dbg.fEnabled, false);
     
    32093191     * Setup the mixer now that we've got the irq and dma channel numbers.
    32103192     */
    3211     pThis->mixer_regs[0x80] = magic_of_irq(pThis->irq);
    3212     pThis->mixer_regs[0x81] = (1 << pThis->dma) | (1 << pThis->hdma);
     3193    pThis->mixer_regs[0x80] = magic_of_irq(pStream->HwCfgRuntime.uIrq);
     3194    pThis->mixer_regs[0x81] = (1 << pStream->HwCfgRuntime.uDmaChanLow) | (1 << pStream->HwCfgRuntime.uDmaChanHigh);
    32133195    pThis->mixer_regs[0x82] = 2 << 5;
    32143196
     
    32303212        AssertRCReturn(rc, rc);
    32313213
    3232         pThis->aStreams[i].cTicksTimerIOInterval = PDMDevHlpTimerGetFreq(pDevIns, pThis->aStreams[i].hTimerIO) / uTimerHz;
     3214        pThis->aStreams[i].cTicksTimerIOInterval = PDMDevHlpTimerGetFreq(pDevIns, pThis->aStreams[i].hTimerIO)
     3215                                                 / pThis->aStreams[i].uTimerHz;
    32333216        pThis->aStreams[i].tsTimerIO             = PDMDevHlpTimerGet(pDevIns, pThis->aStreams[i].hTimerIO);
    32343217    }
     
    32623245    };
    32633246
    3264     rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->port + 0x04 /*uPort*/, 2 /*cPorts*/,
     3247    rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pStream->HwCfgRuntime.uPort + 0x04 /*uPort*/, 2 /*cPorts*/,
    32653248                                     sb16IoPortMixerWrite, sb16IoPortMixerRead,
    32663249                                     "SB16 - Mixer", &s_aAllDescs[4], &pThis->hIoPortsMixer);
    32673250    AssertRCReturn(rc, rc);
    3268     rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->port + 0x06 /*uPort*/, 10 /*cPorts*/,
     3251    rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pStream->HwCfgRuntime.uPort + 0x06 /*uPort*/, 10 /*cPorts*/,
    32693252                                     sb16IoPortDspWrite, sb16IoPortDspRead,
    32703253                                     "SB16 - DSP", &s_aAllDescs[6], &pThis->hIoPortsDsp);
    32713254    AssertRCReturn(rc, rc);
    32723255
    3273     rc = PDMDevHlpDMARegister(pDevIns, pThis->hdma, sb16DMARead, &pThis->aStreams[SB16_IDX_OUT] /* pvUser */);
     3256    rc = PDMDevHlpDMARegister(pDevIns, pStream->HwCfgRuntime.uDmaChanHigh, sb16DMARead, &pThis->aStreams[SB16_IDX_OUT] /* pvUser */);
    32743257    AssertRCReturn(rc, rc);
    3275     rc = PDMDevHlpDMARegister(pDevIns, pThis->dma,  sb16DMARead, &pThis->aStreams[SB16_IDX_OUT] /* pvUser */);
     3258    rc = PDMDevHlpDMARegister(pDevIns, pStream->HwCfgRuntime.uDmaChanLow,  sb16DMARead, &pThis->aStreams[SB16_IDX_OUT] /* pvUser */);
    32763259    AssertRCReturn(rc, rc);
    3277 
    3278     pThis->can_write = 1;
    32793260
    32803261    /*
     
    32873268    LogRel(("SB16: Asynchronous I/O enabled\n"));
    32883269# endif
     3270    LogRel2(("SB16: Using port %#x, DMA%RU8, IRQ%RU8\n",
     3271             pStream->HwCfgRuntime.uPort, pStream->HwCfgRuntime.uDmaChanLow, pStream->HwCfgRuntime.uIrq));
    32893272
    32903273    /*
     
    33053288    }
    33063289
    3307     sb16CmdResetLegacy(pThis);
     3290    sb16DspCmdResetLegacy(pThis);
    33083291
    33093292#ifdef VBOX_WITH_AUDIO_SB16_ONETIME_INIT
     
    33263309            LogRel(("SB16: Falling back to NULL backend (no sound audible)\n"));
    33273310
    3328             sb16CmdResetLegacy(pThis);
     3311            sb16DspCmdResetLegacy(pThis);
    33293312            sb16ReconfigLunWithNullAudio(pThis, pDrv->uLUN);
    33303313            pDrv = NULL; /* no longer valid */
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