VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevSB16.cpp@ 69304

Last change on this file since 69304 was 69288, checked in by vboxsync, 7 years ago

Devices/Audio: scm updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 83.3 KB
Line 
1/* $Id: DevSB16.cpp 69288 2017-10-25 11:32:21Z vboxsync $ */
2/** @file
3 * DevSB16 - VBox SB16 Audio Controller.
4 */
5
6/*
7 * Copyright (C) 2015-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 * --------------------------------------------------------------------
17 *
18 * This code is based on: sb16.c from QEMU AUDIO subsystem (r3917).
19 * QEMU Soundblaster 16 emulation
20 *
21 * Copyright (c) 2003-2005 Vassili Karpov (malc)
22 *
23 * Permission is hereby granted, free of charge, to any person obtaining a copy
24 * of this software and associated documentation files (the "Software"), to deal
25 * in the Software without restriction, including without limitation the rights
26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27 * copies of the Software, and to permit persons to whom the Software is
28 * furnished to do so, subject to the following conditions:
29 *
30 * The above copyright notice and this permission notice shall be included in
31 * all copies or substantial portions of the Software.
32 *
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
36 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39 * THE SOFTWARE.
40 */
41
42
43/*********************************************************************************************************************************
44* Header Files *
45*********************************************************************************************************************************/
46#define LOG_GROUP LOG_GROUP_DEV_SB16
47#include <VBox/log.h>
48#include <iprt/assert.h>
49#include <iprt/file.h>
50#ifdef IN_RING3
51# include <iprt/mem.h>
52# include <iprt/string.h>
53# include <iprt/uuid.h>
54#endif
55
56#include <VBox/vmm/pdmdev.h>
57#include <VBox/vmm/pdmaudioifs.h>
58
59#include "VBoxDD.h"
60
61#include "AudioMixBuffer.h"
62#include "AudioMixer.h"
63#include "DrvAudio.h"
64
65
66/*********************************************************************************************************************************
67* Defined Constants And Macros *
68*********************************************************************************************************************************/
69/** Current saved state version. */
70#define SB16_SAVE_STATE_VERSION 2
71/** The version used in VirtualBox version 3.0 and earlier. This didn't include the config dump. */
72#define SB16_SAVE_STATE_VERSION_VBOX_30 1
73
74#define IO_READ_PROTO(name) \
75 DECLCALLBACK(int) name (PPDMDEVINS pDevIns, void *opaque, \
76 RTIOPORT nport, uint32_t *pu32, unsigned cb)
77
78#define IO_WRITE_PROTO(name) \
79 DECLCALLBACK(int) name (PPDMDEVINS pDevIns, void *opaque, \
80 RTIOPORT nport, uint32_t val, unsigned cb)
81
82
83/*********************************************************************************************************************************
84* Global Variables *
85*********************************************************************************************************************************/
86static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
87
88
89
90/*********************************************************************************************************************************
91* Structures and Typedefs *
92*********************************************************************************************************************************/
93/**
94 * Structure defining a (host backend) driver stream.
95 * Each driver has its own instances of audio mixer streams, which then
96 * can go into the same (or even different) audio mixer sinks.
97 */
98typedef struct SB16DRIVERSTREAM
99{
100 /** Associated PDM audio stream. */
101 R3PTRTYPE(PPDMAUDIOSTREAM) pStream;
102 /** The stream's current configuration. */
103} SB16DRIVERSTREAM, *PSB16DRIVERSTREAM;
104
105/**
106 * Struct for maintaining a host backend driver.
107 */
108typedef struct SB16STATE *PSB16STATE;
109typedef struct SB16DRIVER
110{
111 /** Node for storing this driver in our device driver list of SB16STATE. */
112 RTLISTNODER3 Node;
113 /** Pointer to SB16 controller (state). */
114 R3PTRTYPE(PSB16STATE) pSB16State;
115 /** Driver flags. */
116 PDMAUDIODRVFLAGS fFlags;
117 uint32_t PaddingFlags;
118 /** LUN # to which this driver has been assigned. */
119 uint8_t uLUN;
120 /** Whether this driver is in an attached state or not. */
121 bool fAttached;
122 uint8_t Padding[4];
123 /** Pointer to attached driver base interface. */
124 R3PTRTYPE(PPDMIBASE) pDrvBase;
125 /** Audio connector interface to the underlying host backend. */
126 R3PTRTYPE(PPDMIAUDIOCONNECTOR) pConnector;
127 /** Stream for output. */
128 SB16DRIVERSTREAM Out;
129} SB16DRIVER, *PSB16DRIVER;
130
131/**
132 * Structure for a SB16 stream.
133 */
134typedef struct SB16STREAM
135{
136 /** The stream's current configuration. */
137 PDMAUDIOSTREAMCFG Cfg;
138} SB16STREAM, *PSB16STREAM;
139
140typedef struct SB16STATE
141{
142#ifdef VBOX
143 /** Pointer to the device instance. */
144 PPDMDEVINSR3 pDevInsR3;
145 /** Pointer to the connector of the attached audio driver. */
146 PPDMIAUDIOCONNECTOR pDrv;
147 int irqCfg;
148 int dmaCfg;
149 int hdmaCfg;
150 int portCfg;
151 int verCfg;
152#endif
153 int irq;
154 int dma;
155 int hdma;
156 int port;
157 int ver;
158
159 int in_index;
160 int out_data_len;
161 int fmt_stereo;
162 int fmt_signed;
163 int fmt_bits;
164 PDMAUDIOFMT fmt;
165 int dma_auto;
166 int block_size;
167 int fifo;
168 int freq;
169 int time_const;
170 int speaker;
171 int needed_bytes;
172 int cmd;
173 int use_hdma;
174 int highspeed;
175 int can_write; /** @todo Value never gets 0? */
176
177 int v2x6;
178
179 uint8_t csp_param;
180 uint8_t csp_value;
181 uint8_t csp_mode;
182 uint8_t csp_regs[256];
183 uint8_t csp_index;
184 uint8_t csp_reg83[4];
185 int csp_reg83r;
186 int csp_reg83w;
187
188 uint8_t in2_data[10];
189 uint8_t out_data[50];
190 uint8_t test_reg;
191 uint8_t last_read_byte;
192 int nzero;
193
194 int left_till_irq; /** Note: Can be < 0. */
195
196 int dma_running;
197 int bytes_per_second;
198 int align;
199
200 RTLISTANCHOR lstDrv;
201 /** Number of active (running) SDn streams. */
202 uint8_t cStreamsActive;
203#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
204 /** The timer for pumping data thru the attached LUN drivers. */
205 PTMTIMERR3 pTimerIO;
206 /** Flag indicating whether the timer is active or not. */
207 bool fTimerActive;
208 uint8_t u8Padding1[7];
209 /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
210 uint64_t cTimerTicksIO;
211 /** Timestamp of the last timer callback (sb16TimerIO).
212 * Used to calculate the time actually elapsed between two timer callbacks. */
213 uint64_t uTimerTSIO;
214#endif
215 PTMTIMER pTimerIRQ;
216 /** The base interface for LUN\#0. */
217 PDMIBASE IBase;
218 /** Output stream. */
219 SB16STREAM Out;
220
221 /* mixer state */
222 int mixer_nreg;
223 uint8_t mixer_regs[256];
224} SB16STATE, *PSB16STATE;
225
226
227/*********************************************************************************************************************************
228* Internal Functions *
229*********************************************************************************************************************************/
230static int sb16CreateDrvStream(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg, PSB16DRIVER pDrv);
231static void sb16DestroyDrvStream(PSB16STATE pThis, PSB16DRIVER pDrv);
232static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg);
233static void sb16CloseOut(PSB16STATE pThis);
234#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
235static void sb16TimerMaybeStart(PSB16STATE pThis);
236static void sb16TimerMaybeStop(PSB16STATE pThis);
237#endif
238
239
240
241/**
242 * Attach command, internal version.
243 *
244 * This is called to let the device attach to a driver for a specified LUN
245 * during runtime. This is not called during VM construction, the device
246 * constructor has to attach to all the available drivers.
247 *
248 * @returns VBox status code.
249 * @param pThis SB16 state.
250 * @param uLUN The logical unit which is being detached.
251 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
252 * @param ppDrv Attached driver instance on success. Optional.
253 */
254static int sb16AttachInternal(PSB16STATE pThis, unsigned uLUN, uint32_t fFlags, PSB16DRIVER *ppDrv)
255{
256 RT_NOREF(fFlags);
257
258 /*
259 * Attach driver.
260 */
261 char *pszDesc;
262 if (RTStrAPrintf(&pszDesc, "Audio driver port (SB16) for LUN #%u", uLUN) <= 0)
263 AssertLogRelFailedReturn(VERR_NO_MEMORY);
264
265 PPDMIBASE pDrvBase;
266 int rc = PDMDevHlpDriverAttach(pThis->pDevInsR3, uLUN,
267 &pThis->IBase, &pDrvBase, pszDesc);
268 if (RT_SUCCESS(rc))
269 {
270 PSB16DRIVER pDrv = (PSB16DRIVER)RTMemAllocZ(sizeof(SB16DRIVER));
271 if (pDrv)
272 {
273 pDrv->pDrvBase = pDrvBase;
274 pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
275 AssertMsg(pDrv->pConnector != NULL, ("Configuration error: LUN #%u has no host audio interface, rc=%Rrc\n", uLUN, rc));
276 pDrv->pSB16State = pThis;
277 pDrv->uLUN = uLUN;
278
279 /*
280 * For now we always set the driver at LUN 0 as our primary
281 * host backend. This might change in the future.
282 */
283 if (pDrv->uLUN == 0)
284 pDrv->fFlags |= PDMAUDIODRVFLAGS_PRIMARY;
285
286 LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->fFlags));
287
288 /* Attach to driver list if not attached yet. */
289 if (!pDrv->fAttached)
290 {
291 RTListAppend(&pThis->lstDrv, &pDrv->Node);
292 pDrv->fAttached = true;
293 }
294
295 if (ppDrv)
296 *ppDrv = pDrv;
297 }
298 else
299 rc = VERR_NO_MEMORY;
300 }
301 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
302 LogFunc(("No attached driver for LUN #%u\n", uLUN));
303
304 if (RT_FAILURE(rc))
305 {
306 /* Only free this string on failure;
307 * must remain valid for the live of the driver instance. */
308 RTStrFree(pszDesc);
309 }
310
311 LogFunc(("iLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
312 return rc;
313}
314
315/**
316 * Detach command, internal version.
317 *
318 * This is called to let the device detach from a driver for a specified LUN
319 * during runtime.
320 *
321 * @returns VBox status code.
322 * @param pThis SB16 state.
323 * @param pDrv Driver to detach device from.
324 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
325 */
326static int sb16DetachInternal(PSB16STATE pThis, PSB16DRIVER pDrv, uint32_t fFlags)
327{
328 RT_NOREF(fFlags);
329
330 sb16DestroyDrvStream(pThis, pDrv);
331
332 RTListNodeRemove(&pDrv->Node);
333
334 LogFunc(("uLUN=%u, fFlags=0x%x\n", pDrv->uLUN, fFlags));
335 return VINF_SUCCESS;
336}
337
338/**
339 * @interface_method_impl{PDMDEVREG,pfnAttach}
340 */
341static DECLCALLBACK(int) sb16Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
342{
343 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
344
345 LogFunc(("uLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
346
347 PSB16DRIVER pDrv;
348 int rc2 = sb16AttachInternal(pThis, uLUN, fFlags, &pDrv);
349 if (RT_SUCCESS(rc2))
350 rc2 = sb16CreateDrvStream(pThis, &pThis->Out.Cfg, pDrv);
351
352 return VINF_SUCCESS;
353}
354
355/**
356 * @interface_method_impl{PDMDEVREG,pfnDetach}
357 */
358static DECLCALLBACK(void) sb16Detach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
359{
360 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
361
362 LogFunc(("uLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
363
364 PSB16DRIVER pDrv, pDrvNext;
365 RTListForEachSafe(&pThis->lstDrv, pDrv, pDrvNext, SB16DRIVER, Node)
366 {
367 if (pDrv->uLUN == uLUN)
368 {
369 int rc2 = sb16DetachInternal(pThis, pDrv, fFlags);
370 if (RT_SUCCESS(rc2))
371 {
372 RTMemFree(pDrv);
373 pDrv = NULL;
374 }
375
376 break;
377 }
378 }
379}
380
381/**
382 * Re-attaches (replaces) a driver with a new driver.
383 *
384 * @returns VBox status code.
385 * @param pThis Device instance.
386 * @param pDrv Driver instance used for attaching to.
387 * If NULL is specified, a new driver will be created and appended
388 * to the driver list.
389 * @param uLUN The logical unit which is being re-detached.
390 * @param pszDriver New driver name to attach.
391 */
392static int sb16Reattach(PSB16STATE pThis, PSB16DRIVER pDrv, uint8_t uLUN, const char *pszDriver)
393{
394 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
395 AssertPtrReturn(pszDriver, VERR_INVALID_POINTER);
396
397 int rc;
398
399 if (pDrv)
400 {
401 rc = sb16DetachInternal(pThis, pDrv, 0 /* fFlags */);
402 if (RT_SUCCESS(rc))
403 rc = PDMDevHlpDriverDetach(pThis->pDevInsR3, PDMIBASE_2_PDMDRV(pDrv->pDrvBase), 0 /* fFlags */);
404
405 if (RT_FAILURE(rc))
406 return rc;
407
408 pDrv = NULL;
409 }
410
411 PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
412 PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
413 PCFGMNODE pDev0 = CFGMR3GetChild(pRoot, "Devices/sb16/0/");
414
415 /* Remove LUN branch. */
416 CFGMR3RemoveNode(CFGMR3GetChildF(pDev0, "LUN#%u/", uLUN));
417
418 if (pDrv)
419 {
420 /* Re-use the driver instance so detach it before. */
421 rc = PDMDevHlpDriverDetach(pThis->pDevInsR3, PDMIBASE_2_PDMDRV(pDrv->pDrvBase), 0 /* fFlags */);
422 if (RT_FAILURE(rc))
423 return rc;
424 }
425
426#define RC_CHECK() if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; }
427
428 do
429 {
430 PCFGMNODE pLunL0;
431 rc = CFGMR3InsertNodeF(pDev0, &pLunL0, "LUN#%u/", uLUN); RC_CHECK();
432 rc = CFGMR3InsertString(pLunL0, "Driver", "AUDIO"); RC_CHECK();
433 rc = CFGMR3InsertNode(pLunL0, "Config/", NULL); RC_CHECK();
434
435 PCFGMNODE pLunL1, pLunL2;
436 rc = CFGMR3InsertNode (pLunL0, "AttachedDriver/", &pLunL1); RC_CHECK();
437 rc = CFGMR3InsertNode (pLunL1, "Config/", &pLunL2); RC_CHECK();
438 rc = CFGMR3InsertString(pLunL1, "Driver", pszDriver); RC_CHECK();
439
440 rc = CFGMR3InsertString(pLunL2, "AudioDriver", pszDriver); RC_CHECK();
441
442 } while (0);
443
444 if (RT_SUCCESS(rc))
445 rc = sb16AttachInternal(pThis, uLUN, 0 /* fFlags */, NULL /* ppDrv */);
446
447 LogFunc(("pThis=%p, uLUN=%u, pszDriver=%s, rc=%Rrc\n", pThis, uLUN, pszDriver, rc));
448
449#undef RC_CHECK
450
451 return rc;
452}
453
454static int magic_of_irq(int irq)
455{
456 switch (irq)
457 {
458 case 5:
459 return 2;
460 case 7:
461 return 4;
462 case 9:
463 return 1;
464 case 10:
465 return 8;
466 default:
467 break;
468 }
469
470 LogFlowFunc(("bad irq %d\n", irq));
471 return 2;
472}
473
474static int irq_of_magic(int magic)
475{
476 switch (magic)
477 {
478 case 1:
479 return 9;
480 case 2:
481 return 5;
482 case 4:
483 return 7;
484 case 8:
485 return 10;
486 default:
487 break;
488 }
489
490 LogFlowFunc(("bad irq magic %d\n", magic));
491 return -1;
492}
493
494#if 0 // unused // def DEBUG
495DECLINLINE(void) log_dsp(PSB16STATE pThis)
496{
497 LogFlowFunc(("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
498 pThis->fmt_stereo ? "Stereo" : "Mono",
499 pThis->fmt_signed ? "Signed" : "Unsigned",
500 pThis->fmt_bits,
501 pThis->dma_auto ? "Auto" : "Single",
502 pThis->block_size,
503 pThis->freq,
504 pThis->time_const,
505 pThis->speaker));
506}
507#endif
508
509static void sb16SpeakerControl(PSB16STATE pThis, int on)
510{
511 pThis->speaker = on;
512 /* AUD_enable (pThis->voice, on); */
513}
514
515static void sb16Control(PSB16STATE pThis, int hold)
516{
517 int dma = pThis->use_hdma ? pThis->hdma : pThis->dma;
518 pThis->dma_running = hold;
519
520 LogFlowFunc(("hold %d high %d dma %d\n", hold, pThis->use_hdma, dma));
521
522 PDMDevHlpDMASetDREQ(pThis->pDevInsR3, dma, hold);
523
524 PSB16DRIVER pDrv;
525 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
526 {
527 if (!pDrv->Out.pStream)
528 continue;
529
530 int rc2 = pDrv->pConnector->pfnStreamControl(pDrv->pConnector, pDrv->Out.pStream,
531 hold == 1 ? PDMAUDIOSTREAMCMD_ENABLE : PDMAUDIOSTREAMCMD_DISABLE);
532 LogFlowFunc(("%s: rc=%Rrc\n", pDrv->Out.pStream->szName, rc2)); NOREF(rc2);
533 }
534
535 if (hold)
536 {
537#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
538 pThis->cStreamsActive++;
539 sb16TimerMaybeStart(pThis);
540#else
541# error "Implement me!"
542#endif
543 PDMDevHlpDMASchedule(pThis->pDevInsR3);
544 }
545#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
546 else
547 {
548 if (pThis->cStreamsActive)
549 pThis->cStreamsActive--;
550 sb16TimerMaybeStop(pThis);
551 }
552#else
553# error "Implement me!"
554#endif
555}
556
557static DECLCALLBACK(void) sb16TimerIRQ(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvThis)
558{
559 RT_NOREF(pDevIns, pTimer);
560 PSB16STATE pThis = (PSB16STATE)pvThis;
561 pThis->can_write = 1;
562 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
563}
564
565#define DMA8_AUTO 1
566#define DMA8_HIGH 2
567
568static void continue_dma8(PSB16STATE pThis)
569{
570 if (pThis->freq > 0)
571 {
572 /* At the moment we only have one stream, the output stream. */
573 PPDMAUDIOSTREAMCFG pCfg = &pThis->Out.Cfg;
574
575 pCfg->enmDir = PDMAUDIODIR_OUT;
576 pCfg->DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
577 pCfg->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
578
579 pCfg->Props.uHz = pThis->freq;
580 pCfg->Props.cChannels = 1 << pThis->fmt_stereo;
581 pCfg->Props.cBits = pThis->fmt_bits;
582 pCfg->Props.fSigned = RT_BOOL(pThis->fmt_signed);
583 pCfg->Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cBits, pCfg->Props.cChannels);
584
585 RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "Output");
586
587 sb16CloseOut(pThis);
588
589 int rc = sb16OpenOut(pThis, pCfg);
590 AssertRC(rc);
591 }
592
593 sb16Control(pThis, 1);
594}
595
596static void dma_cmd8(PSB16STATE pThis, int mask, int dma_len)
597{
598 pThis->fmt = PDMAUDIOFMT_U8;
599 pThis->use_hdma = 0;
600 pThis->fmt_bits = 8;
601 pThis->fmt_signed = 0;
602 pThis->fmt_stereo = (pThis->mixer_regs[0x0e] & 2) != 0;
603
604 if (-1 == pThis->time_const)
605 {
606 if (pThis->freq <= 0)
607 pThis->freq = 11025;
608 }
609 else
610 {
611 int tmp = (256 - pThis->time_const);
612 pThis->freq = (1000000 + (tmp / 2)) / tmp;
613 }
614
615 if (dma_len != -1)
616 {
617 pThis->block_size = dma_len << pThis->fmt_stereo;
618 }
619 else
620 {
621 /* This is apparently the only way to make both Act1/PL
622 and SecondReality/FC work
623
624 r=andy Wow, actually someone who remembers Future Crew :-)
625
626 Act1 sets block size via command 0x48 and it's an odd number
627 SR does the same with even number
628 Both use stereo, and Creatives own documentation states that
629 0x48 sets block size in bytes less one.. go figure */
630 pThis->block_size &= ~pThis->fmt_stereo;
631 }
632
633 pThis->freq >>= pThis->fmt_stereo;
634 pThis->left_till_irq = pThis->block_size;
635 pThis->bytes_per_second = (pThis->freq << pThis->fmt_stereo);
636 /* pThis->highspeed = (mask & DMA8_HIGH) != 0; */
637 pThis->dma_auto = (mask & DMA8_AUTO) != 0;
638 pThis->align = (1 << pThis->fmt_stereo) - 1;
639
640 if (pThis->block_size & pThis->align)
641 LogFlowFunc(("warning: misaligned block size %d, alignment %d\n",
642 pThis->block_size, pThis->align + 1));
643
644 LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, dma %d, auto %d, fifo %d, high %d\n",
645 pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
646 pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
647
648 continue_dma8(pThis);
649 sb16SpeakerControl(pThis, 1);
650}
651
652static void dma_cmd(PSB16STATE pThis, uint8_t cmd, uint8_t d0, int dma_len)
653{
654 pThis->use_hdma = cmd < 0xc0;
655 pThis->fifo = (cmd >> 1) & 1;
656 pThis->dma_auto = (cmd >> 2) & 1;
657 pThis->fmt_signed = (d0 >> 4) & 1;
658 pThis->fmt_stereo = (d0 >> 5) & 1;
659
660 switch (cmd >> 4)
661 {
662 case 11:
663 pThis->fmt_bits = 16;
664 break;
665
666 case 12:
667 pThis->fmt_bits = 8;
668 break;
669 }
670
671 if (-1 != pThis->time_const)
672 {
673#if 1
674 int tmp = 256 - pThis->time_const;
675 pThis->freq = (1000000 + (tmp / 2)) / tmp;
676#else
677 /* pThis->freq = 1000000 / ((255 - pThis->time_const) << pThis->fmt_stereo); */
678 pThis->freq = 1000000 / ((255 - pThis->time_const));
679#endif
680 pThis->time_const = -1;
681 }
682
683 pThis->block_size = dma_len + 1;
684 pThis->block_size <<= ((pThis->fmt_bits == 16) ? 1 : 0);
685 if (!pThis->dma_auto)
686 {
687 /*
688 * It is clear that for DOOM and auto-init this value
689 * shouldn't take stereo into account, while Miles Sound Systems
690 * setsound.exe with single transfer mode wouldn't work without it
691 * wonders of SB16 yet again.
692 */
693 pThis->block_size <<= pThis->fmt_stereo;
694 }
695
696 LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, dma %d, auto %d, fifo %d, high %d\n",
697 pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
698 pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
699
700 if (16 == pThis->fmt_bits)
701 pThis->fmt = pThis->fmt_signed ? PDMAUDIOFMT_S16 : PDMAUDIOFMT_U16;
702 else
703 pThis->fmt = pThis->fmt_signed ? PDMAUDIOFMT_S8 : PDMAUDIOFMT_U8;
704
705 pThis->left_till_irq = pThis->block_size;
706
707 pThis->bytes_per_second = (pThis->freq << pThis->fmt_stereo) << ((pThis->fmt_bits == 16) ? 1 : 0);
708 pThis->highspeed = 0;
709 pThis->align = (1 << (pThis->fmt_stereo + (pThis->fmt_bits == 16))) - 1;
710 if (pThis->block_size & pThis->align)
711 {
712 LogFlowFunc(("warning: misaligned block size %d, alignment %d\n",
713 pThis->block_size, pThis->align + 1));
714 }
715
716 if (pThis->freq)
717 {
718 /* At the moment we only have one stream, the output stream. */
719 PPDMAUDIOSTREAMCFG pCfg = &pThis->Out.Cfg;
720
721 pCfg->enmDir = PDMAUDIODIR_OUT;
722 pCfg->DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
723 pCfg->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
724
725 pCfg->Props.uHz = pThis->freq;
726 pCfg->Props.cChannels = 1 << pThis->fmt_stereo;
727 pCfg->Props.cBits = pThis->fmt_bits;
728 pCfg->Props.fSigned = RT_BOOL(pThis->fmt_signed);
729 pCfg->Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cBits, pCfg->Props.cChannels);
730
731 RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "Output");
732
733 sb16CloseOut(pThis);
734
735 int rc = sb16OpenOut(pThis, pCfg);
736 AssertRC(rc);
737 }
738
739 sb16Control(pThis, 1);
740 sb16SpeakerControl(pThis, 1);
741}
742
743static inline void dsp_out_data (PSB16STATE pThis, uint8_t val)
744{
745 LogFlowFunc(("outdata %#x\n", val));
746 if ((size_t) pThis->out_data_len < sizeof (pThis->out_data)) {
747 pThis->out_data[pThis->out_data_len++] = val;
748 }
749}
750
751static inline uint8_t dsp_get_data (PSB16STATE pThis)
752{
753 if (pThis->in_index) {
754 return pThis->in2_data[--pThis->in_index];
755 }
756 else {
757 LogFlowFunc(("buffer underflow\n"));
758 return 0;
759 }
760}
761
762static void sb16HandleCommand(PSB16STATE pThis, uint8_t cmd)
763{
764 LogFlowFunc(("command %#x\n", cmd));
765
766 if (cmd > 0xaf && cmd < 0xd0)
767 {
768 if (cmd & 8) /** @todo Handle recording. */
769 LogFlowFunc(("ADC not yet supported (command %#x)\n", cmd));
770
771 switch (cmd >> 4)
772 {
773 case 11:
774 case 12:
775 break;
776 default:
777 LogFlowFunc(("%#x wrong bits\n", cmd));
778 }
779
780 pThis->needed_bytes = 3;
781 }
782 else
783 {
784 pThis->needed_bytes = 0;
785
786 switch (cmd)
787 {
788 case 0x03:
789 dsp_out_data(pThis, 0x10); /* pThis->csp_param); */
790 goto warn;
791
792 case 0x04:
793 pThis->needed_bytes = 1;
794 goto warn;
795
796 case 0x05:
797 pThis->needed_bytes = 2;
798 goto warn;
799
800 case 0x08:
801 /* __asm__ ("int3"); */
802 goto warn;
803
804 case 0x0e:
805 pThis->needed_bytes = 2;
806 goto warn;
807
808 case 0x09:
809 dsp_out_data(pThis, 0xf8);
810 goto warn;
811
812 case 0x0f:
813 pThis->needed_bytes = 1;
814 goto warn;
815
816 case 0x10:
817 pThis->needed_bytes = 1;
818 goto warn;
819
820 case 0x14:
821 pThis->needed_bytes = 2;
822 pThis->block_size = 0;
823 break;
824
825 case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */
826 dma_cmd8(pThis, DMA8_AUTO, -1);
827 break;
828
829 case 0x20: /* Direct ADC, Juice/PL */
830 dsp_out_data(pThis, 0xff);
831 goto warn;
832
833 case 0x35:
834 LogFlowFunc(("0x35 - MIDI command not implemented\n"));
835 break;
836
837 case 0x40:
838 pThis->freq = -1;
839 pThis->time_const = -1;
840 pThis->needed_bytes = 1;
841 break;
842
843 case 0x41:
844 pThis->freq = -1;
845 pThis->time_const = -1;
846 pThis->needed_bytes = 2;
847 break;
848
849 case 0x42:
850 pThis->freq = -1;
851 pThis->time_const = -1;
852 pThis->needed_bytes = 2;
853 goto warn;
854
855 case 0x45:
856 dsp_out_data(pThis, 0xaa);
857 goto warn;
858
859 case 0x47: /* Continue Auto-Initialize DMA 16bit */
860 break;
861
862 case 0x48:
863 pThis->needed_bytes = 2;
864 break;
865
866 case 0x74:
867 pThis->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
868 LogFlowFunc(("0x75 - DMA DAC, 4-bit ADPCM not implemented\n"));
869 break;
870
871 case 0x75: /* DMA DAC, 4-bit ADPCM Reference */
872 pThis->needed_bytes = 2;
873 LogFlowFunc(("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n"));
874 break;
875
876 case 0x76: /* DMA DAC, 2.6-bit ADPCM */
877 pThis->needed_bytes = 2;
878 LogFlowFunc(("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n"));
879 break;
880
881 case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */
882 pThis->needed_bytes = 2;
883 LogFlowFunc(("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n"));
884 break;
885
886 case 0x7d:
887 LogFlowFunc(("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n"));
888 LogFlowFunc(("not implemented\n"));
889 break;
890
891 case 0x7f:
892 LogFlowFunc(("0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"));
893 LogFlowFunc(("not implemented\n"));
894 break;
895
896 case 0x80:
897 pThis->needed_bytes = 2;
898 break;
899
900 case 0x90:
901 case 0x91:
902 dma_cmd8(pThis, (((cmd & 1) == 0) ? 1 : 0) | DMA8_HIGH, -1);
903 break;
904
905 case 0xd0: /* halt DMA operation. 8bit */
906 sb16Control(pThis, 0);
907 break;
908
909 case 0xd1: /* speaker on */
910 sb16SpeakerControl(pThis, 1);
911 break;
912
913 case 0xd3: /* speaker off */
914 sb16SpeakerControl(pThis, 0);
915 break;
916
917 case 0xd4: /* continue DMA operation. 8bit */
918 /* KQ6 (or maybe Sierras audblst.drv in general) resets
919 the frequency between halt/continue */
920 continue_dma8(pThis);
921 break;
922
923 case 0xd5: /* halt DMA operation. 16bit */
924 sb16Control(pThis, 0);
925 break;
926
927 case 0xd6: /* continue DMA operation. 16bit */
928 sb16Control(pThis, 1);
929 break;
930
931 case 0xd9: /* exit auto-init DMA after this block. 16bit */
932 pThis->dma_auto = 0;
933 break;
934
935 case 0xda: /* exit auto-init DMA after this block. 8bit */
936 pThis->dma_auto = 0;
937 break;
938
939 case 0xe0: /* DSP identification */
940 pThis->needed_bytes = 1;
941 break;
942
943 case 0xe1:
944 dsp_out_data(pThis, pThis->ver & 0xff);
945 dsp_out_data(pThis, pThis->ver >> 8);
946 break;
947
948 case 0xe2:
949 pThis->needed_bytes = 1;
950 goto warn;
951
952 case 0xe3:
953 {
954 for (int i = sizeof (e3) - 1; i >= 0; --i)
955 dsp_out_data(pThis, e3[i]);
956
957 break;
958 }
959
960 case 0xe4: /* write test reg */
961 pThis->needed_bytes = 1;
962 break;
963
964 case 0xe7:
965 LogFlowFunc(("Attempt to probe for ESS (0xe7)?\n"));
966 break;
967
968 case 0xe8: /* read test reg */
969 dsp_out_data(pThis, pThis->test_reg);
970 break;
971
972 case 0xf2:
973 case 0xf3:
974 dsp_out_data(pThis, 0xaa);
975 pThis->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
976 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
977 break;
978
979 case 0xf8:
980 /* Undocumented, used by old Creative diagnostic programs. */
981 dsp_out_data (pThis, 0);
982 goto warn;
983
984 case 0xf9:
985 pThis->needed_bytes = 1;
986 goto warn;
987
988 case 0xfa:
989 dsp_out_data (pThis, 0);
990 goto warn;
991
992 case 0xfc: /* FIXME */
993 dsp_out_data (pThis, 0);
994 goto warn;
995
996 default:
997 LogFlowFunc(("Unrecognized command %#x\n", cmd));
998 break;
999 }
1000 }
1001
1002 if (!pThis->needed_bytes)
1003 LogFlow(("\n"));
1004
1005exit:
1006
1007 if (!pThis->needed_bytes)
1008 pThis->cmd = -1;
1009 else
1010 pThis->cmd = cmd;
1011
1012 return;
1013
1014warn:
1015 LogFlowFunc(("warning: command %#x,%d is not truly understood yet\n",
1016 cmd, pThis->needed_bytes));
1017 goto exit;
1018}
1019
1020static uint16_t dsp_get_lohi (PSB16STATE pThis)
1021{
1022 uint8_t hi = dsp_get_data (pThis);
1023 uint8_t lo = dsp_get_data (pThis);
1024 return (hi << 8) | lo;
1025}
1026
1027static uint16_t dsp_get_hilo (PSB16STATE pThis)
1028{
1029 uint8_t lo = dsp_get_data (pThis);
1030 uint8_t hi = dsp_get_data (pThis);
1031 return (hi << 8) | lo;
1032}
1033
1034static void complete(PSB16STATE pThis)
1035{
1036 int d0, d1, d2;
1037 LogFlowFunc(("complete command %#x, in_index %d, needed_bytes %d\n",
1038 pThis->cmd, pThis->in_index, pThis->needed_bytes));
1039
1040 if (pThis->cmd > 0xaf && pThis->cmd < 0xd0)
1041 {
1042 d2 = dsp_get_data (pThis);
1043 d1 = dsp_get_data (pThis);
1044 d0 = dsp_get_data (pThis);
1045
1046 if (pThis->cmd & 8)
1047 LogFlowFunc(("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", pThis->cmd, d0, d1, d2));
1048 else
1049 {
1050 LogFlowFunc(("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", pThis->cmd, d0, d1, d2));
1051 dma_cmd(pThis, pThis->cmd, d0, d1 + (d2 << 8));
1052 }
1053 }
1054 else
1055 {
1056 switch (pThis->cmd)
1057 {
1058 case 0x04:
1059 pThis->csp_mode = dsp_get_data (pThis);
1060 pThis->csp_reg83r = 0;
1061 pThis->csp_reg83w = 0;
1062 LogFlowFunc(("CSP command 0x04: mode=%#x\n", pThis->csp_mode));
1063 break;
1064
1065 case 0x05:
1066 pThis->csp_param = dsp_get_data (pThis);
1067 pThis->csp_value = dsp_get_data (pThis);
1068 LogFlowFunc(("CSP command 0x05: param=%#x value=%#x\n",
1069 pThis->csp_param,
1070 pThis->csp_value));
1071 break;
1072
1073 case 0x0e:
1074 {
1075 d0 = dsp_get_data(pThis);
1076 d1 = dsp_get_data(pThis);
1077 LogFlowFunc(("write CSP register %d <- %#x\n", d1, d0));
1078 if (d1 == 0x83)
1079 {
1080 LogFlowFunc(("0x83[%d] <- %#x\n", pThis->csp_reg83r, d0));
1081 pThis->csp_reg83[pThis->csp_reg83r % 4] = d0;
1082 pThis->csp_reg83r += 1;
1083 }
1084 else
1085 pThis->csp_regs[d1] = d0;
1086 break;
1087 }
1088
1089 case 0x0f:
1090 d0 = dsp_get_data(pThis);
1091 LogFlowFunc(("read CSP register %#x -> %#x, mode=%#x\n", d0, pThis->csp_regs[d0], pThis->csp_mode));
1092 if (d0 == 0x83)
1093 {
1094 LogFlowFunc(("0x83[%d] -> %#x\n",
1095 pThis->csp_reg83w,
1096 pThis->csp_reg83[pThis->csp_reg83w % 4]));
1097 dsp_out_data (pThis, pThis->csp_reg83[pThis->csp_reg83w % 4]);
1098 pThis->csp_reg83w += 1;
1099 }
1100 else
1101 dsp_out_data(pThis, pThis->csp_regs[d0]);
1102 break;
1103
1104 case 0x10:
1105 d0 = dsp_get_data(pThis);
1106 LogFlowFunc(("cmd 0x10 d0=%#x\n", d0));
1107 break;
1108
1109 case 0x14:
1110 dma_cmd8(pThis, 0, dsp_get_lohi (pThis) + 1);
1111 break;
1112
1113 case 0x40:
1114 pThis->time_const = dsp_get_data(pThis);
1115 LogFlowFunc(("set time const %d\n", pThis->time_const));
1116 break;
1117
1118 case 0x42: /* FT2 sets output freq with this, go figure */
1119#if 0
1120 LogFlowFunc(("cmd 0x42 might not do what it think it should\n"));
1121#endif
1122 case 0x41:
1123 pThis->freq = dsp_get_hilo(pThis);
1124 LogFlowFunc(("set freq %d\n", pThis->freq));
1125 break;
1126
1127 case 0x48:
1128 pThis->block_size = dsp_get_lohi(pThis) + 1;
1129 LogFlowFunc(("set dma block len %d\n", pThis->block_size));
1130 break;
1131
1132 case 0x74:
1133 case 0x75:
1134 case 0x76:
1135 case 0x77:
1136 /* ADPCM stuff, ignore */
1137 break;
1138
1139 case 0x80:
1140 {
1141 int freq, samples, bytes;
1142 uint64_t ticks;
1143
1144 freq = pThis->freq > 0 ? pThis->freq : 11025;
1145 samples = dsp_get_lohi (pThis) + 1;
1146 bytes = samples << pThis->fmt_stereo << ((pThis->fmt_bits == 16) ? 1 : 0);
1147 ticks = (bytes * TMTimerGetFreq(pThis->pTimerIRQ)) / freq;
1148 if (ticks < TMTimerGetFreq(pThis->pTimerIRQ) / 1024)
1149 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
1150 else
1151 TMTimerSet(pThis->pTimerIRQ, TMTimerGet(pThis->pTimerIRQ) + ticks);
1152 LogFlowFunc(("mix silence: %d samples, %d bytes, %RU64 ticks\n", samples, bytes, ticks));
1153 break;
1154 }
1155
1156 case 0xe0:
1157 d0 = dsp_get_data(pThis);
1158 pThis->out_data_len = 0;
1159 LogFlowFunc(("E0 data = %#x\n", d0));
1160 dsp_out_data(pThis, ~d0);
1161 break;
1162
1163 case 0xe2:
1164 d0 = dsp_get_data(pThis);
1165 LogFlow(("SB16:E2 = %#x\n", d0));
1166 break;
1167
1168 case 0xe4:
1169 pThis->test_reg = dsp_get_data(pThis);
1170 break;
1171
1172 case 0xf9:
1173 d0 = dsp_get_data(pThis);
1174 LogFlowFunc(("command 0xf9 with %#x\n", d0));
1175 switch (d0) {
1176 case 0x0e:
1177 dsp_out_data(pThis, 0xff);
1178 break;
1179
1180 case 0x0f:
1181 dsp_out_data(pThis, 0x07);
1182 break;
1183
1184 case 0x37:
1185 dsp_out_data(pThis, 0x38);
1186 break;
1187
1188 default:
1189 dsp_out_data(pThis, 0x00);
1190 break;
1191 }
1192 break;
1193
1194 default:
1195 LogFlowFunc(("complete: unrecognized command %#x\n", pThis->cmd));
1196 return;
1197 }
1198 }
1199
1200 LogFlow(("\n"));
1201 pThis->cmd = -1;
1202 return;
1203}
1204
1205static uint8_t sb16MixRegToVol(PSB16STATE pThis, int reg)
1206{
1207 /* The SB16 mixer has a 0 to -62dB range in 32 levels (2dB each step).
1208 * We use a 0 to -96dB range in 256 levels (0.375dB each step).
1209 * Only the top 5 bits of a mixer register are used.
1210 */
1211 uint8_t steps = 31 - (pThis->mixer_regs[reg] >> 3);
1212 uint8_t vol = 255 - steps * 16 / 3; /* (2dB*8) / (0.375dB*8) */
1213 return vol;
1214}
1215
1216static void sb16SetMasterVolume(PSB16STATE pThis)
1217{
1218 /* There's no mute switch, only volume controls. */
1219 uint8_t lvol = sb16MixRegToVol(pThis, 0x30);
1220 uint8_t rvol = sb16MixRegToVol(pThis, 0x31);
1221
1222 PDMAUDIOVOLUME Vol = { false /* fMute */, lvol, rvol };
1223
1224 PSB16DRIVER pDrv;
1225 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1226 {
1227 int rc2 = pDrv->pConnector->pfnStreamSetVolume(pDrv->pConnector, pDrv->Out.pStream, &Vol);
1228 AssertRC(rc2);
1229 }
1230}
1231
1232static void sb16SetPcmOutVolume(PSB16STATE pThis)
1233{
1234 /* There's no mute switch, only volume controls. */
1235 uint8_t lvol = sb16MixRegToVol(pThis, 0x32);
1236 uint8_t rvol = sb16MixRegToVol(pThis, 0x33);
1237
1238 PDMAUDIOVOLUME Vol = { false /* fMute */, lvol, rvol };
1239
1240 PSB16DRIVER pDrv;
1241 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1242 {
1243 int rc2 = pDrv->pConnector->pfnStreamSetVolume(pDrv->pConnector, pDrv->Out.pStream, &Vol);
1244 AssertRC(rc2);
1245 }
1246}
1247
1248static void sb16ResetLegacy(PSB16STATE pThis)
1249{
1250 LogFlowFuncEnter();
1251
1252 sb16CloseOut(pThis);
1253
1254 pThis->freq = 11025;
1255 pThis->fmt_signed = 0;
1256 pThis->fmt_bits = 8;
1257 pThis->fmt_stereo = 0;
1258
1259 /* At the moment we only have one stream, the output stream. */
1260 PPDMAUDIOSTREAMCFG pCfg = &pThis->Out.Cfg;
1261
1262 pCfg->enmDir = PDMAUDIODIR_OUT;
1263 pCfg->DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
1264 pCfg->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
1265
1266 pCfg->Props.uHz = pThis->freq;
1267 pCfg->Props.cChannels = 1; /* Mono */
1268 pCfg->Props.cBits = 8;
1269 pCfg->Props.fSigned = false;
1270 pCfg->Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cBits, pCfg->Props.cChannels);
1271
1272 RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "Output");
1273
1274 sb16CloseOut(pThis);
1275
1276 int rc2 = sb16OpenOut(pThis, pCfg);
1277 AssertRC(rc2);
1278}
1279
1280static void sb16Reset(PSB16STATE pThis)
1281{
1282 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
1283 if (pThis->dma_auto)
1284 {
1285 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
1286 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
1287 }
1288
1289 pThis->mixer_regs[0x82] = 0;
1290 pThis->dma_auto = 0;
1291 pThis->in_index = 0;
1292 pThis->out_data_len = 0;
1293 pThis->left_till_irq = 0;
1294 pThis->needed_bytes = 0;
1295 pThis->block_size = -1;
1296 pThis->nzero = 0;
1297 pThis->highspeed = 0;
1298 pThis->v2x6 = 0;
1299 pThis->cmd = -1;
1300
1301 dsp_out_data(pThis, 0xaa);
1302 sb16SpeakerControl(pThis, 0);
1303
1304 sb16Control(pThis, 0);
1305 sb16ResetLegacy(pThis);
1306}
1307
1308static IO_WRITE_PROTO(dsp_write)
1309{
1310 RT_NOREF(pDevIns, cb);
1311 PSB16STATE pThis = (PSB16STATE)opaque;
1312 int iport = nport - pThis->port;
1313
1314 LogFlowFunc(("write %#x <- %#x\n", nport, val));
1315 switch (iport)
1316 {
1317 case 0x06:
1318 switch (val)
1319 {
1320 case 0x00:
1321 {
1322 if (pThis->v2x6 == 1)
1323 {
1324 if (0 && pThis->highspeed)
1325 {
1326 pThis->highspeed = 0;
1327 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
1328 sb16Control(pThis, 0);
1329 }
1330 else
1331 sb16Reset(pThis);
1332 }
1333 pThis->v2x6 = 0;
1334 break;
1335 }
1336
1337 case 0x01:
1338 case 0x03: /* FreeBSD kludge */
1339 pThis->v2x6 = 1;
1340 break;
1341
1342 case 0xc6:
1343 pThis->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */
1344 break;
1345
1346 case 0xb8: /* Panic */
1347 sb16Reset(pThis);
1348 break;
1349
1350 case 0x39:
1351 dsp_out_data(pThis, 0x38);
1352 sb16Reset(pThis);
1353 pThis->v2x6 = 0x39;
1354 break;
1355
1356 default:
1357 pThis->v2x6 = val;
1358 break;
1359 }
1360 break;
1361
1362 case 0x0c: /* Write data or command | write status */
1363#if 0
1364 if (pThis->highspeed)
1365 break;
1366#endif
1367 if (0 == pThis->needed_bytes)
1368 {
1369 sb16HandleCommand(pThis, val);
1370#if 0
1371 if (0 == pThis->needed_bytes) {
1372 log_dsp (pThis);
1373 }
1374#endif
1375 }
1376 else
1377 {
1378 if (pThis->in_index == sizeof (pThis->in2_data))
1379 {
1380 LogFlowFunc(("in data overrun\n"));
1381 }
1382 else
1383 {
1384 pThis->in2_data[pThis->in_index++] = val;
1385 if (pThis->in_index == pThis->needed_bytes)
1386 {
1387 pThis->needed_bytes = 0;
1388 complete (pThis);
1389#if 0
1390 log_dsp (pThis);
1391#endif
1392 }
1393 }
1394 }
1395 break;
1396
1397 default:
1398 LogFlowFunc(("nport=%#x, val=%#x)\n", nport, val));
1399 break;
1400 }
1401
1402 return VINF_SUCCESS;
1403}
1404
1405static IO_READ_PROTO(dsp_read)
1406{
1407 RT_NOREF(pDevIns, cb);
1408 PSB16STATE pThis = (PSB16STATE)opaque;
1409 int iport, retval, ack = 0;
1410
1411 iport = nport - pThis->port;
1412
1413 /** @todo reject non-byte access?
1414 * The spec does not mention a non-byte access so we should check how real hardware behaves. */
1415
1416 switch (iport)
1417 {
1418 case 0x06: /* reset */
1419 retval = 0xff;
1420 break;
1421
1422 case 0x0a: /* read data */
1423 if (pThis->out_data_len)
1424 {
1425 retval = pThis->out_data[--pThis->out_data_len];
1426 pThis->last_read_byte = retval;
1427 }
1428 else
1429 {
1430 if (pThis->cmd != -1)
1431 LogFlowFunc(("empty output buffer for command %#x\n", pThis->cmd));
1432 retval = pThis->last_read_byte;
1433 /* goto error; */
1434 }
1435 break;
1436
1437 case 0x0c: /* 0 can write */
1438 retval = pThis->can_write ? 0 : 0x80;
1439 break;
1440
1441 case 0x0d: /* timer interrupt clear */
1442 /* LogFlowFunc(("timer interrupt clear\n")); */
1443 retval = 0;
1444 break;
1445
1446 case 0x0e: /* data available status | irq 8 ack */
1447 retval = (!pThis->out_data_len || pThis->highspeed) ? 0 : 0x80;
1448 if (pThis->mixer_regs[0x82] & 1)
1449 {
1450 ack = 1;
1451 pThis->mixer_regs[0x82] &= ~1;
1452 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
1453 }
1454 break;
1455
1456 case 0x0f: /* irq 16 ack */
1457 retval = 0xff;
1458 if (pThis->mixer_regs[0x82] & 2)
1459 {
1460 ack = 1;
1461 pThis->mixer_regs[0x82] &= ~2;
1462 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
1463 }
1464 break;
1465
1466 default:
1467 goto error;
1468 }
1469
1470 if (!ack)
1471 LogFlowFunc(("read %#x -> %#x\n", nport, retval));
1472
1473 *pu32 = retval;
1474 return VINF_SUCCESS;
1475
1476 error:
1477 LogFlowFunc(("warning: dsp_read %#x error\n", nport));
1478 return VERR_IOM_IOPORT_UNUSED;
1479}
1480
1481static void sb16MixerReset(PSB16STATE pThis)
1482{
1483 memset(pThis->mixer_regs, 0xff, 0x7f);
1484 memset(pThis->mixer_regs + 0x83, 0xff, sizeof (pThis->mixer_regs) - 0x83);
1485
1486 pThis->mixer_regs[0x02] = 4; /* master volume 3bits */
1487 pThis->mixer_regs[0x06] = 4; /* MIDI volume 3bits */
1488 pThis->mixer_regs[0x08] = 0; /* CD volume 3bits */
1489 pThis->mixer_regs[0x0a] = 0; /* voice volume 2bits */
1490
1491 /* d5=input filt, d3=lowpass filt, d1,d2=input source */
1492 pThis->mixer_regs[0x0c] = 0;
1493
1494 /* d5=output filt, d1=stereo switch */
1495 pThis->mixer_regs[0x0e] = 0;
1496
1497 /* voice volume L d5,d7, R d1,d3 */
1498 pThis->mixer_regs[0x04] = (12 << 4) | 12;
1499 /* master ... */
1500 pThis->mixer_regs[0x22] = (12 << 4) | 12;
1501 /* MIDI ... */
1502 pThis->mixer_regs[0x26] = (12 << 4) | 12;
1503
1504 /* master/voice/MIDI L/R volume */
1505 for (int i = 0x30; i < 0x36; i++)
1506 pThis->mixer_regs[i] = 24 << 3; /* -14 dB */
1507
1508 /* treble/bass */
1509 for (int i = 0x44; i < 0x48; i++)
1510 pThis->mixer_regs[i] = 0x80;
1511
1512 /* Update the master (mixer) and PCM out volumes. */
1513 sb16SetMasterVolume(pThis);
1514 sb16SetPcmOutVolume(pThis);
1515}
1516
1517static IO_WRITE_PROTO(mixer_write_indexb)
1518{
1519 RT_NOREF(pDevIns, cb);
1520 PSB16STATE pThis = (PSB16STATE)opaque;
1521 (void) nport;
1522 pThis->mixer_nreg = val;
1523
1524 return VINF_SUCCESS;
1525}
1526
1527uint32_t popcount(uint32_t u) /** @todo r=andy WTF? */
1528{
1529 u = ((u&0x55555555) + ((u>>1)&0x55555555));
1530 u = ((u&0x33333333) + ((u>>2)&0x33333333));
1531 u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
1532 u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
1533 u = ( u&0x0000ffff) + (u>>16);
1534 return u;
1535}
1536
1537uint32_t lsbindex(uint32_t u)
1538{
1539 return popcount((u & -(int32_t)u) - 1);
1540}
1541
1542/* Convert SB16 to SB Pro mixer volume (left). */
1543static inline void sb16ConvVolumeL(PSB16STATE pThis, unsigned reg, uint8_t val)
1544{
1545 /* High nibble in SBP mixer. */
1546 pThis->mixer_regs[reg] = (pThis->mixer_regs[reg] & 0x0f) | (val & 0xf0);
1547}
1548
1549/* Convert SB16 to SB Pro mixer volume (right). */
1550static inline void sb16ConvVolumeR(PSB16STATE pThis, unsigned reg, uint8_t val)
1551{
1552 /* Low nibble in SBP mixer. */
1553 pThis->mixer_regs[reg] = (pThis->mixer_regs[reg] & 0xf0) | (val >> 4);
1554}
1555
1556/* Convert SB Pro to SB16 mixer volume (left + right). */
1557static inline void sb16ConvVolumeOldToNew(PSB16STATE pThis, unsigned reg, uint8_t val)
1558{
1559 /* Left channel. */
1560 pThis->mixer_regs[reg + 0] = (val & 0xf0) | RT_BIT(3);
1561 /* Right channel (the register immediately following). */
1562 pThis->mixer_regs[reg + 1] = (val << 4) | RT_BIT(3);
1563}
1564
1565static IO_WRITE_PROTO(mixer_write_datab)
1566{
1567 RT_NOREF(pDevIns, cb);
1568 PSB16STATE pThis = (PSB16STATE)opaque;
1569 bool fUpdateMaster = false;
1570 bool fUpdateStream = false;
1571
1572 (void) nport;
1573 LogFlowFunc(("mixer_write [%#x] <- %#x\n", pThis->mixer_nreg, val));
1574
1575 switch (pThis->mixer_nreg)
1576 {
1577 case 0x00:
1578 sb16MixerReset(pThis);
1579 /* And update the actual volume, too. */
1580 fUpdateMaster = true;
1581 fUpdateStream = true;
1582 break;
1583
1584 case 0x04: /* Translate from old style voice volume (L/R). */
1585 sb16ConvVolumeOldToNew(pThis, 0x32, val);
1586 fUpdateStream = true;
1587 break;
1588
1589 case 0x22: /* Translate from old style master volume (L/R). */
1590 sb16ConvVolumeOldToNew(pThis, 0x30, val);
1591 fUpdateMaster = true;
1592 break;
1593
1594 case 0x26: /* Translate from old style MIDI volume (L/R). */
1595 sb16ConvVolumeOldToNew(pThis, 0x34, val);
1596 break;
1597
1598 case 0x28: /* Translate from old style CD volume (L/R). */
1599 sb16ConvVolumeOldToNew(pThis, 0x36, val);
1600 break;
1601
1602 case 0x2E: /* Translate from old style line volume (L/R). */
1603 sb16ConvVolumeOldToNew(pThis, 0x38, val);
1604 break;
1605
1606 case 0x30: /* Translate to old style master volume (L). */
1607 sb16ConvVolumeL(pThis, 0x22, val);
1608 fUpdateMaster = true;
1609 break;
1610
1611 case 0x31: /* Translate to old style master volume (R). */
1612 sb16ConvVolumeR(pThis, 0x22, val);
1613 fUpdateMaster = true;
1614 break;
1615
1616 case 0x32: /* Translate to old style voice volume (L). */
1617 sb16ConvVolumeL(pThis, 0x04, val);
1618 fUpdateStream = true;
1619 break;
1620
1621 case 0x33: /* Translate to old style voice volume (R). */
1622 sb16ConvVolumeR(pThis, 0x04, val);
1623 fUpdateStream = true;
1624 break;
1625
1626 case 0x34: /* Translate to old style MIDI volume (L). */
1627 sb16ConvVolumeL(pThis, 0x26, val);
1628 break;
1629
1630 case 0x35: /* Translate to old style MIDI volume (R). */
1631 sb16ConvVolumeR(pThis, 0x26, val);
1632 break;
1633
1634 case 0x36: /* Translate to old style CD volume (L). */
1635 sb16ConvVolumeL(pThis, 0x28, val);
1636 break;
1637
1638 case 0x37: /* Translate to old style CD volume (R). */
1639 sb16ConvVolumeR(pThis, 0x28, val);
1640 break;
1641
1642 case 0x38: /* Translate to old style line volume (L). */
1643 sb16ConvVolumeL(pThis, 0x2E, val);
1644 break;
1645
1646 case 0x39: /* Translate to old style line volume (R). */
1647 sb16ConvVolumeR(pThis, 0x2E, val);
1648 break;
1649
1650 case 0x80:
1651 {
1652 int irq = irq_of_magic(val);
1653 LogFlowFunc(("setting irq to %d (val=%#x)\n", irq, val));
1654 if (irq > 0)
1655 pThis->irq = irq;
1656 break;
1657 }
1658
1659 case 0x81:
1660 {
1661 int dma, hdma;
1662
1663 dma = lsbindex (val & 0xf);
1664 hdma = lsbindex (val & 0xf0);
1665 if (dma != pThis->dma || hdma != pThis->hdma)
1666 LogFlow(("SB16: attempt to change DMA 8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
1667 dma, pThis->dma, hdma, pThis->hdma, val));
1668#if 0
1669 pThis->dma = dma;
1670 pThis->hdma = hdma;
1671#endif
1672 break;
1673 }
1674
1675 case 0x82:
1676 LogFlowFunc(("attempt to write into IRQ status register (val=%#x)\n", val));
1677 return VINF_SUCCESS;
1678
1679 default:
1680 if (pThis->mixer_nreg >= 0x80)
1681 LogFlowFunc(("attempt to write mixer[%#x] <- %#x\n", pThis->mixer_nreg, val));
1682 break;
1683 }
1684
1685 pThis->mixer_regs[pThis->mixer_nreg] = val;
1686
1687 /* Update the master (mixer) volume. */
1688 if (fUpdateMaster)
1689 sb16SetMasterVolume(pThis);
1690
1691 /* Update the stream (PCM) volume. */
1692 if (fUpdateStream)
1693 sb16SetPcmOutVolume(pThis);
1694
1695 return VINF_SUCCESS;
1696}
1697
1698static IO_WRITE_PROTO(mixer_write)
1699{
1700 PSB16STATE pThis = (PSB16STATE)opaque;
1701 int iport = nport - pThis->port;
1702 switch (cb)
1703 {
1704 case 1:
1705 switch (iport)
1706 {
1707 case 4:
1708 mixer_write_indexb (pDevIns, opaque, nport, val, 1);
1709 break;
1710 case 5:
1711 mixer_write_datab (pDevIns, opaque, nport, val, 1);
1712 break;
1713 }
1714 break;
1715 case 2:
1716 mixer_write_indexb (pDevIns, opaque, nport, val & 0xff, 1);
1717 mixer_write_datab (pDevIns, opaque, nport, (val >> 8) & 0xff, 1);
1718 break;
1719 default:
1720 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", nport, cb, val));
1721 break;
1722 }
1723 return VINF_SUCCESS;
1724}
1725
1726static IO_READ_PROTO(mixer_read)
1727{
1728 RT_NOREF(pDevIns, cb);
1729 PSB16STATE pThis = (PSB16STATE)opaque;
1730
1731 (void) nport;
1732#ifndef DEBUG_SB16_MOST
1733 if (pThis->mixer_nreg != 0x82) {
1734 LogFlowFunc(("mixer_read[%#x] -> %#x\n",
1735 pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
1736 }
1737#else
1738 LogFlowFunc(("mixer_read[%#x] -> %#x\n",
1739 pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
1740#endif
1741 *pu32 = pThis->mixer_regs[pThis->mixer_nreg];
1742 return VINF_SUCCESS;
1743}
1744
1745static int sb16WriteAudio(PSB16STATE pThis, int nchan, uint32_t dma_pos,
1746 uint32_t dma_len, int len)
1747{
1748 uint8_t tmpbuf[_4K]; /** @todo Have a buffer on the heap. */
1749 uint32_t cbToWrite = len;
1750 uint32_t cbWrittenTotal = 0;
1751
1752 while (cbToWrite)
1753 {
1754 uint32_t cbToRead = RT_MIN(dma_len - dma_pos, cbToWrite);
1755 if (cbToRead > sizeof(tmpbuf))
1756 cbToRead = sizeof(tmpbuf);
1757
1758 uint32_t cbRead = 0;
1759 int rc2 = PDMDevHlpDMAReadMemory(pThis->pDevInsR3, nchan, tmpbuf, dma_pos, cbToRead, &cbRead);
1760 AssertMsgRC(rc2, (" from DMA failed: %Rrc\n", rc2));
1761
1762#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
1763 if (cbRead)
1764 {
1765 RTFILE fh;
1766 RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "sb16WriteAudio.pcm",
1767 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1768 RTFileWrite(fh, tmpbuf, cbRead, NULL);
1769 RTFileClose(fh);
1770 }
1771#endif
1772 /*
1773 * Write data to the backends.
1774 */
1775 uint32_t cbWritten = 0;
1776
1777 /* Just multiplex the output to the connected backends.
1778 * No need to utilize the virtual mixer here (yet). */
1779 PSB16DRIVER pDrv;
1780 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1781 {
1782 uint32_t cbWrittenToStream = 0;
1783 rc2 = pDrv->pConnector->pfnStreamWrite(pDrv->pConnector, pDrv->Out.pStream, tmpbuf, cbRead, &cbWrittenToStream);
1784
1785 LogFlowFunc(("\tLUN#%RU8: rc=%Rrc, cbWrittenToStream=%RU32\n", pDrv->uLUN, rc2, cbWrittenToStream));
1786
1787 /* The primary driver sets the overall pace. */
1788 if (pDrv->fFlags & PDMAUDIODRVFLAGS_PRIMARY)
1789 {
1790 cbWritten = cbWrittenToStream;
1791
1792 if (RT_FAILURE(rc2))
1793 break;
1794 }
1795 }
1796
1797 LogFlowFunc(("\tcbToRead=%RU32, cbToWrite=%RU32, cbWritten=%RU32, cbLeft=%RU32\n",
1798 cbToRead, cbToWrite, cbWritten, cbToWrite - cbWrittenTotal));
1799
1800 Assert(cbToWrite >= cbWritten);
1801 cbToWrite -= cbWritten;
1802 dma_pos = (dma_pos + cbWritten) % dma_len;
1803 cbWrittenTotal += cbWritten;
1804
1805 if (!cbWritten)
1806 break;
1807 }
1808
1809 return cbWrittenTotal;
1810}
1811
1812static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
1813{
1814 RT_NOREF(pDevIns);
1815 PSB16STATE pThis = (PSB16STATE)opaque;
1816 int till, copy, written, free;
1817
1818 if (pThis->block_size <= 0)
1819 {
1820 LogFlowFunc(("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
1821 pThis->block_size, nchan, dma_pos, dma_len));
1822 return dma_pos;
1823 }
1824
1825 if (pThis->left_till_irq < 0)
1826 pThis->left_till_irq = pThis->block_size;
1827
1828 uint32_t cbOutMin = UINT32_MAX;
1829
1830 PSB16DRIVER pDrv;
1831 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1832 {
1833 uint32_t cbOut = pDrv->pConnector->pfnStreamGetWritable(pDrv->pConnector, pDrv->Out.pStream);
1834
1835 if (cbOut < cbOutMin)
1836 cbOutMin = cbOut;
1837 }
1838
1839 LogFlowFunc(("cbOutMin=%RU32\n", cbOutMin));
1840 if (cbOutMin == UINT32_MAX)
1841 {
1842 free = dma_len;
1843 }
1844 else
1845 {
1846 free = cbOutMin & ~pThis->align; /** @todo int vs. uint32. */
1847 if ((free <= 0) || !dma_len)
1848 return dma_pos;
1849 }
1850
1851 copy = free;
1852 till = pThis->left_till_irq;
1853
1854#ifdef DEBUG_SB16_MOST
1855 LogFlowFunc(("pos:%06d %d till:%d len:%d\n", dma_pos, free, till, dma_len));
1856#endif
1857
1858 if (copy >= till)
1859 {
1860 if (0 == pThis->dma_auto)
1861 {
1862 copy = till;
1863 }
1864 else
1865 {
1866 if (copy >= till + pThis->block_size)
1867 copy = till; /* Make sure we won't skip IRQs. */
1868 }
1869 }
1870
1871 written = sb16WriteAudio(pThis, nchan, dma_pos, dma_len, copy);
1872 dma_pos = (dma_pos + written) % dma_len;
1873 pThis->left_till_irq -= written;
1874
1875 if (pThis->left_till_irq <= 0)
1876 {
1877 pThis->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
1878 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
1879 if (0 == pThis->dma_auto)
1880 {
1881 sb16Control(pThis, 0);
1882 sb16SpeakerControl(pThis, 0);
1883 }
1884 }
1885
1886 Log3Func(("pos %d/%d free %5d till %5d copy %5d written %5d block_size %5d\n",
1887 dma_pos, dma_len, free, pThis->left_till_irq, copy, written,
1888 pThis->block_size));
1889
1890 while (pThis->left_till_irq <= 0)
1891 pThis->left_till_irq += pThis->block_size;
1892
1893 return dma_pos;
1894}
1895
1896#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
1897static void sb16TimerMaybeStart(PSB16STATE pThis)
1898{
1899 LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
1900
1901 if (pThis->cStreamsActive == 0) /* Only start the timer if there are no active streams. */
1902 return;
1903
1904 if (!pThis->pTimerIO)
1905 return;
1906
1907 /* Set timer flag. */
1908 ASMAtomicXchgBool(&pThis->fTimerActive, true);
1909
1910 /* Update current time timestamp. */
1911 pThis->uTimerTSIO = TMTimerGet(pThis->pTimerIO);
1912
1913 /* Fire off timer. */
1914 TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->cTimerTicksIO);
1915}
1916
1917static void sb16TimerMaybeStop(PSB16STATE pThis)
1918{
1919 LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
1920
1921 if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
1922 return;
1923
1924 if (!pThis->pTimerIO)
1925 return;
1926
1927 /* Set timer flag. */
1928 ASMAtomicXchgBool(&pThis->fTimerActive, false);
1929}
1930
1931static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1932{
1933 RT_NOREF(pDevIns);
1934 PSB16STATE pThis = (PSB16STATE)pvUser;
1935 Assert(pThis == PDMINS_2_DATA(pDevIns, PSB16STATE));
1936 AssertPtr(pThis);
1937
1938 uint64_t cTicksNow = TMTimerGet(pTimer);
1939 bool fIsPlaying = false; /* Whether one or more streams are still playing. */
1940 bool fDoTransfer = false;
1941
1942 pThis->uTimerTSIO = cTicksNow;
1943
1944 PSB16DRIVER pDrv;
1945 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1946 {
1947 PPDMAUDIOSTREAM pStream = pDrv->Out.pStream;
1948 if (!pStream)
1949 continue;
1950
1951#ifdef DEBUG
1952 PSB16DRIVER pDrvPrev = RTListNodeGetPrev(&pDrv->Node, SB16DRIVER, Node);
1953 if ( pDrvPrev
1954 && !RTListNodeIsDummy(&pThis->lstDrv, pDrvPrev, SB16DRIVER, Node))
1955 {
1956 PPDMAUDIOSTREAM pStreamPrev = pDrvPrev->Out.pStream;
1957 AssertPtr(pStreamPrev);
1958
1959 /*
1960 * Sanity. Make sure that all streams have the same configuration
1961 * to get SB16's DMA transfers right.
1962 *
1963 * SB16 only allows one output configuration per serial data out,
1964 * so check if all streams have the same configuration.
1965 */
1966 AssertMsg(pStream->Cfg.Props.uHz == pStreamPrev->Cfg.Props.uHz,
1967 ("%RU32Hz vs. %RU32Hz\n", pStream->Cfg.Props.uHz, pStreamPrev->Cfg.Props.uHz));
1968 AssertMsg(pStream->Cfg.Props.cChannels == pStreamPrev->Cfg.Props.cChannels,
1969 ("%RU8 vs. %RU8 channels\n", pStream->Cfg.Props.cChannels, pStreamPrev->Cfg.Props.cChannels));
1970 AssertMsg(pStream->Cfg.Props.cBits == pStreamPrev->Cfg.Props.cBits,
1971 ("%d vs. %d bits\n", pStream->Cfg.Props.cBits, pStreamPrev->Cfg.Props.cBits));
1972 AssertMsg(pStream->Cfg.Props.fSigned == pStreamPrev->Cfg.Props.fSigned,
1973 ("%RTbool vs. %RTbool signed\n", pStream->Cfg.Props.fSigned, pStreamPrev->Cfg.Props.fSigned));
1974 }
1975#endif
1976 PPDMIAUDIOCONNECTOR pConn = pDrv->pConnector;
1977 if (!pConn)
1978 continue;
1979
1980 int rc2 = pConn->pfnStreamIterate(pConn, pStream);
1981 if (RT_SUCCESS(rc2))
1982 {
1983 if (pStream->enmDir == PDMAUDIODIR_IN)
1984 {
1985 /** @todo Implement recording! */
1986 }
1987 else
1988 {
1989 rc2 = pConn->pfnStreamPlay(pConn, pStream, NULL /* cPlayed */);
1990 if (RT_FAILURE(rc2))
1991 {
1992 LogFlowFunc(("%s: Failed playing stream, rc=%Rrc\n", pStream->szName, rc2));
1993 continue;
1994 }
1995 }
1996
1997 if (pDrv->fFlags & PDMAUDIODRVFLAGS_PRIMARY)
1998 {
1999 /* Only do the next DMA transfer if we're able to write the remaining data block. */
2000 fDoTransfer = pConn->pfnStreamGetWritable(pConn, pStream) > (unsigned)pThis->left_till_irq;
2001 }
2002 }
2003
2004 PDMAUDIOSTREAMSTS strmSts = pConn->pfnStreamGetStatus(pConn, pStream);
2005 fIsPlaying |= ( (strmSts & PDMAUDIOSTREAMSTS_FLAG_ENABLED)
2006 || (strmSts & PDMAUDIOSTREAMSTS_FLAG_PENDING_DISABLE));
2007 }
2008
2009 bool fTimerActive = ASMAtomicReadBool(&pThis->fTimerActive);
2010 bool fKickTimer = fTimerActive || fIsPlaying;
2011
2012 LogFlowFunc(("fTimerActive=%RTbool, fIsPlaying=%RTbool\n", fTimerActive, fIsPlaying));
2013
2014 if (fDoTransfer)
2015 {
2016 /* Schedule the next transfer. */
2017 PDMDevHlpDMASchedule(pThis->pDevInsR3);
2018
2019 /* Kick the timer at least one more time. */
2020 fKickTimer = true;
2021 }
2022
2023 /*
2024 * Recording.
2025 */
2026 /** @todo Implement recording. */
2027
2028 if (fKickTimer)
2029 {
2030 /* Kick the timer again. */
2031 uint64_t cTicks = pThis->cTimerTicksIO;
2032 /** @todo adjust cTicks down by now much cbOutMin represents. */
2033 TMTimerSet(pThis->pTimerIO, cTicksNow + cTicks);
2034 }
2035}
2036#endif /* !VBOX_WITH_AUDIO_SB16_CALLBACKS */
2037
2038static void sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis)
2039{
2040 SSMR3PutS32(pSSM, pThis->irq);
2041 SSMR3PutS32(pSSM, pThis->dma);
2042 SSMR3PutS32(pSSM, pThis->hdma);
2043 SSMR3PutS32(pSSM, pThis->port);
2044 SSMR3PutS32(pSSM, pThis->ver);
2045 SSMR3PutS32(pSSM, pThis->in_index);
2046 SSMR3PutS32(pSSM, pThis->out_data_len);
2047 SSMR3PutS32(pSSM, pThis->fmt_stereo);
2048 SSMR3PutS32(pSSM, pThis->fmt_signed);
2049 SSMR3PutS32(pSSM, pThis->fmt_bits);
2050
2051 SSMR3PutU32(pSSM, pThis->fmt);
2052
2053 SSMR3PutS32(pSSM, pThis->dma_auto);
2054 SSMR3PutS32(pSSM, pThis->block_size);
2055 SSMR3PutS32(pSSM, pThis->fifo);
2056 SSMR3PutS32(pSSM, pThis->freq);
2057 SSMR3PutS32(pSSM, pThis->time_const);
2058 SSMR3PutS32(pSSM, pThis->speaker);
2059 SSMR3PutS32(pSSM, pThis->needed_bytes);
2060 SSMR3PutS32(pSSM, pThis->cmd);
2061 SSMR3PutS32(pSSM, pThis->use_hdma);
2062 SSMR3PutS32(pSSM, pThis->highspeed);
2063 SSMR3PutS32(pSSM, pThis->can_write);
2064 SSMR3PutS32(pSSM, pThis->v2x6);
2065
2066 SSMR3PutU8 (pSSM, pThis->csp_param);
2067 SSMR3PutU8 (pSSM, pThis->csp_value);
2068 SSMR3PutU8 (pSSM, pThis->csp_mode);
2069 SSMR3PutU8 (pSSM, pThis->csp_param); /* Bug compatible! */
2070 SSMR3PutMem(pSSM, pThis->csp_regs, 256);
2071 SSMR3PutU8 (pSSM, pThis->csp_index);
2072 SSMR3PutMem(pSSM, pThis->csp_reg83, 4);
2073 SSMR3PutS32(pSSM, pThis->csp_reg83r);
2074 SSMR3PutS32(pSSM, pThis->csp_reg83w);
2075
2076 SSMR3PutMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
2077 SSMR3PutMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
2078 SSMR3PutU8 (pSSM, pThis->test_reg);
2079 SSMR3PutU8 (pSSM, pThis->last_read_byte);
2080
2081 SSMR3PutS32(pSSM, pThis->nzero);
2082 SSMR3PutS32(pSSM, pThis->left_till_irq);
2083 SSMR3PutS32(pSSM, pThis->dma_running);
2084 SSMR3PutS32(pSSM, pThis->bytes_per_second);
2085 SSMR3PutS32(pSSM, pThis->align);
2086
2087 SSMR3PutS32(pSSM, pThis->mixer_nreg);
2088 SSMR3PutMem(pSSM, pThis->mixer_regs, 256);
2089
2090}
2091
2092static int sb16Load(PSSMHANDLE pSSM, PSB16STATE pThis)
2093{
2094 SSMR3GetS32(pSSM, &pThis->irq);
2095 SSMR3GetS32(pSSM, &pThis->dma);
2096 SSMR3GetS32(pSSM, &pThis->hdma);
2097 SSMR3GetS32(pSSM, &pThis->port);
2098 SSMR3GetS32(pSSM, &pThis->ver);
2099 SSMR3GetS32(pSSM, &pThis->in_index);
2100 SSMR3GetS32(pSSM, &pThis->out_data_len);
2101 SSMR3GetS32(pSSM, &pThis->fmt_stereo);
2102 SSMR3GetS32(pSSM, &pThis->fmt_signed);
2103 SSMR3GetS32(pSSM, &pThis->fmt_bits);
2104
2105 SSMR3GetU32(pSSM, (uint32_t *)&pThis->fmt);
2106
2107 SSMR3GetS32(pSSM, &pThis->dma_auto);
2108 SSMR3GetS32(pSSM, &pThis->block_size);
2109 SSMR3GetS32(pSSM, &pThis->fifo);
2110 SSMR3GetS32(pSSM, &pThis->freq);
2111 SSMR3GetS32(pSSM, &pThis->time_const);
2112 SSMR3GetS32(pSSM, &pThis->speaker);
2113 SSMR3GetS32(pSSM, &pThis->needed_bytes);
2114 SSMR3GetS32(pSSM, &pThis->cmd);
2115 SSMR3GetS32(pSSM, &pThis->use_hdma);
2116 SSMR3GetS32(pSSM, &pThis->highspeed);
2117 SSMR3GetS32(pSSM, &pThis->can_write);
2118 SSMR3GetS32(pSSM, &pThis->v2x6);
2119
2120 SSMR3GetU8 (pSSM, &pThis->csp_param);
2121 SSMR3GetU8 (pSSM, &pThis->csp_value);
2122 SSMR3GetU8 (pSSM, &pThis->csp_mode);
2123 SSMR3GetU8 (pSSM, &pThis->csp_param); /* Bug compatible! */
2124 SSMR3GetMem(pSSM, pThis->csp_regs, 256);
2125 SSMR3GetU8 (pSSM, &pThis->csp_index);
2126 SSMR3GetMem(pSSM, pThis->csp_reg83, 4);
2127 SSMR3GetS32(pSSM, &pThis->csp_reg83r);
2128 SSMR3GetS32(pSSM, &pThis->csp_reg83w);
2129
2130 SSMR3GetMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
2131 SSMR3GetMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
2132 SSMR3GetU8 (pSSM, &pThis->test_reg);
2133 SSMR3GetU8 (pSSM, &pThis->last_read_byte);
2134
2135 SSMR3GetS32(pSSM, &pThis->nzero);
2136 SSMR3GetS32(pSSM, &pThis->left_till_irq);
2137 SSMR3GetS32(pSSM, &pThis->dma_running);
2138 SSMR3GetS32(pSSM, &pThis->bytes_per_second);
2139 SSMR3GetS32(pSSM, &pThis->align);
2140
2141 SSMR3GetS32(pSSM, &pThis->mixer_nreg);
2142 SSMR3GetMem(pSSM, pThis->mixer_regs, 256);
2143
2144#if 0
2145 PSB16DRIVER pDrv;
2146 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2147 {
2148 if (pDrv->Out.pStream)
2149 {
2150 pDrv->pConnector->pfnCloseOut(pThis->pDrv, pDrv->Out.pStream);
2151 pDrv->Out.pStream = NULL;
2152 }
2153 }
2154#endif
2155
2156 if (pThis->dma_running)
2157 {
2158 if (pThis->freq)
2159 {
2160 /* At the moment we only have one stream, the output stream. */
2161 PPDMAUDIOSTREAMCFG pCfg = &pThis->Out.Cfg;
2162
2163 pCfg->enmDir = PDMAUDIODIR_OUT;
2164 pCfg->DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
2165 pCfg->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
2166
2167 pCfg->Props.uHz = pThis->freq;
2168 pCfg->Props.cChannels = 1 << pThis->fmt_stereo;
2169 pCfg->Props.cBits = pThis->fmt_bits;
2170 pCfg->Props.fSigned = RT_BOOL(pThis->fmt_signed);
2171 pCfg->Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cBits, pCfg->Props.cChannels);
2172
2173 RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "Output");
2174
2175 sb16CloseOut(pThis);
2176
2177 int rc = sb16OpenOut(pThis, pCfg);
2178 AssertRC(rc);
2179 }
2180
2181 sb16Control(pThis, 1);
2182 sb16SpeakerControl(pThis, pThis->speaker);
2183 }
2184
2185 /* Update the master (mixer) and PCM out volumes. */
2186 sb16SetMasterVolume(pThis);
2187 sb16SetPcmOutVolume(pThis);
2188
2189 return VINF_SUCCESS;
2190}
2191
2192static DECLCALLBACK(int) sb16LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
2193{
2194 RT_NOREF(uPass);
2195 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2196
2197 SSMR3PutS32(pSSM, pThis->irqCfg);
2198 SSMR3PutS32(pSSM, pThis->dmaCfg);
2199 SSMR3PutS32(pSSM, pThis->hdmaCfg);
2200 SSMR3PutS32(pSSM, pThis->portCfg);
2201 SSMR3PutS32(pSSM, pThis->verCfg);
2202 return VINF_SSM_DONT_CALL_AGAIN;
2203}
2204
2205static DECLCALLBACK(int) sb16SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2206{
2207 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2208
2209 sb16LiveExec(pDevIns, pSSM, 0);
2210 sb16Save(pSSM, pThis);
2211 return VINF_SUCCESS;
2212}
2213
2214static DECLCALLBACK(int) sb16LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2215{
2216 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2217
2218 AssertMsgReturn( uVersion == SB16_SAVE_STATE_VERSION
2219 || uVersion == SB16_SAVE_STATE_VERSION_VBOX_30,
2220 ("%u\n", uVersion),
2221 VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
2222 if (uVersion > SB16_SAVE_STATE_VERSION_VBOX_30)
2223 {
2224 int32_t irq;
2225 SSMR3GetS32 (pSSM, &irq);
2226 int32_t dma;
2227 SSMR3GetS32 (pSSM, &dma);
2228 int32_t hdma;
2229 SSMR3GetS32 (pSSM, &hdma);
2230 int32_t port;
2231 SSMR3GetS32 (pSSM, &port);
2232 int32_t ver;
2233 int rc = SSMR3GetS32 (pSSM, &ver);
2234 AssertRCReturn (rc, rc);
2235
2236 if ( irq != pThis->irqCfg
2237 || dma != pThis->dmaCfg
2238 || hdma != pThis->hdmaCfg
2239 || port != pThis->portCfg
2240 || ver != pThis->verCfg)
2241 {
2242 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
2243 N_("config changed: irq=%x/%x dma=%x/%x hdma=%x/%x port=%x/%x ver=%x/%x (saved/config)"),
2244 irq, pThis->irqCfg,
2245 dma, pThis->dmaCfg,
2246 hdma, pThis->hdmaCfg,
2247 port, pThis->portCfg,
2248 ver, pThis->verCfg);
2249 }
2250 }
2251
2252 if (uPass != SSM_PASS_FINAL)
2253 return VINF_SUCCESS;
2254
2255 sb16Load(pSSM, pThis);
2256 return VINF_SUCCESS;
2257}
2258
2259/**
2260 * Creates a PDM audio stream for a specific driver.
2261 *
2262 * @returns IPRT status code.
2263 * @param pThis SB16 state.
2264 * @param pCfg Stream configuration to use.
2265 * @param pDrv Driver stream to create PDM stream for.
2266 */
2267static int sb16CreateDrvStream(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg, PSB16DRIVER pDrv)
2268{
2269 RT_NOREF(pThis);
2270
2271 AssertReturn(pCfg->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER);
2272 Assert(DrvAudioHlpStreamCfgIsValid(pCfg));
2273
2274 PPDMAUDIOSTREAMCFG pCfgHost = DrvAudioHlpStreamCfgDup(pCfg);
2275 if (!pCfgHost)
2276 return VERR_NO_MEMORY;
2277
2278 if (!RTStrPrintf(pCfgHost->szName, sizeof(pCfgHost->szName), "%s", pCfg->szName))
2279 {
2280 RTMemFree(pCfgHost);
2281 return VERR_BUFFER_OVERFLOW;
2282 }
2283
2284 LogFunc(("[LUN#%RU8] %s\n", pDrv->uLUN, pCfgHost->szName));
2285
2286 AssertMsg(pDrv->Out.pStream == NULL, ("[LUN#%RU8] Driver stream already present when it must not\n", pDrv->uLUN));
2287
2288 int rc = pDrv->pConnector->pfnStreamCreate(pDrv->pConnector, pCfgHost, pCfg /* pCfgGuest */, &pDrv->Out.pStream);
2289 if (RT_SUCCESS(rc))
2290 {
2291 pDrv->pConnector->pfnStreamRetain(pDrv->pConnector, pDrv->Out.pStream);
2292 LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc));
2293 }
2294
2295 if (pCfgHost)
2296 {
2297 RTMemFree(pCfgHost);
2298 pCfgHost = NULL;
2299 }
2300
2301 return rc;
2302}
2303
2304/**
2305 * Destroys a PDM audio stream of a specific driver.
2306 *
2307 * @param pThis SB16 state.
2308 * @param pDrv Driver stream to destroy PDM stream for.
2309 */
2310static void sb16DestroyDrvStream(PSB16STATE pThis, PSB16DRIVER pDrv)
2311{
2312 AssertPtrReturnVoid(pThis);
2313 AssertPtrReturnVoid(pDrv);
2314
2315 if (pDrv->Out.pStream)
2316 {
2317 pDrv->pConnector->pfnStreamRelease(pDrv->pConnector, pDrv->Out.pStream);
2318
2319 int rc2 = pDrv->pConnector->pfnStreamDestroy(pDrv->pConnector, pDrv->Out.pStream);
2320 if (RT_SUCCESS(rc2))
2321 pDrv->Out.pStream = NULL;
2322 }
2323}
2324
2325static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg)
2326{
2327 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2328 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2329
2330 LogFlowFuncEnter();
2331
2332 if (!DrvAudioHlpStreamCfgIsValid(pCfg))
2333 return VERR_INVALID_PARAMETER;
2334
2335 int rc = VINF_SUCCESS;
2336
2337 PSB16DRIVER pDrv;
2338 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2339 {
2340 int rc2 = sb16CreateDrvStream(pThis, pCfg, pDrv);
2341 if (RT_SUCCESS(rc))
2342 rc = rc2;
2343 }
2344
2345 LogFlowFuncLeaveRC(rc);
2346 return rc;
2347}
2348
2349static void sb16CloseOut(PSB16STATE pThis)
2350{
2351 AssertPtrReturnVoid(pThis);
2352
2353 LogFlowFuncEnter();
2354
2355 PSB16DRIVER pDrv;
2356 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2357 sb16DestroyDrvStream(pThis, pDrv);
2358
2359 LogFlowFuncLeave();
2360}
2361
2362/**
2363 * @interface_method_impl{PDMDEVREG,pfnReset}
2364 */
2365static DECLCALLBACK(void) sb16DevReset(PPDMDEVINS pDevIns)
2366{
2367 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2368
2369 /* Bring back the device to initial state, and especially make
2370 * sure there's no interrupt or DMA activity.
2371 */
2372 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
2373
2374 pThis->mixer_regs[0x82] = 0;
2375 pThis->csp_regs[5] = 1;
2376 pThis->csp_regs[9] = 0xf8;
2377
2378 pThis->dma_auto = 0;
2379 pThis->in_index = 0;
2380 pThis->out_data_len = 0;
2381 pThis->left_till_irq = 0;
2382 pThis->needed_bytes = 0;
2383 pThis->block_size = -1;
2384 pThis->nzero = 0;
2385 pThis->highspeed = 0;
2386 pThis->v2x6 = 0;
2387 pThis->cmd = -1;
2388
2389 sb16MixerReset(pThis);
2390 sb16SpeakerControl(pThis, 0);
2391 sb16Control(pThis, 0);
2392 sb16ResetLegacy(pThis);
2393}
2394
2395/**
2396 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2397 */
2398static DECLCALLBACK(void *) sb16QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
2399{
2400 PSB16STATE pThis = RT_FROM_MEMBER(pInterface, SB16STATE, IBase);
2401 Assert(&pThis->IBase == pInterface);
2402
2403 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2404 return NULL;
2405}
2406
2407/**
2408 * Powers off the device.
2409 *
2410 * @param pDevIns Device instance to power off.
2411 */
2412static DECLCALLBACK(void) sb16PowerOff(PPDMDEVINS pDevIns)
2413{
2414 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2415
2416 LogRel2(("SB16: Powering off ...\n"));
2417
2418 PSB16DRIVER pDrv;
2419 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2420 {
2421 if (pDrv->Out.pStream)
2422 {
2423 pDrv->pConnector->pfnStreamRelease(pDrv->pConnector, pDrv->Out.pStream);
2424
2425 int rc2 = pDrv->pConnector->pfnStreamDestroy(pDrv->pConnector, pDrv->Out.pStream);
2426 if (RT_SUCCESS(rc2))
2427 pDrv->Out.pStream = NULL;
2428 }
2429 }
2430}
2431
2432/**
2433 * @interface_method_impl{PDMDEVREG,pfnDestruct}
2434 */
2435static DECLCALLBACK(int) sb16Destruct(PPDMDEVINS pDevIns)
2436{
2437 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2438 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2439
2440 LogFlowFuncEnter();
2441
2442 PSB16DRIVER pDrv;
2443 while (!RTListIsEmpty(&pThis->lstDrv))
2444 {
2445 pDrv = RTListGetFirst(&pThis->lstDrv, SB16DRIVER, Node);
2446
2447 RTListNodeRemove(&pDrv->Node);
2448 RTMemFree(pDrv);
2449 }
2450
2451 return VINF_SUCCESS;
2452}
2453
2454static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2455{
2456 RT_NOREF(iInstance);
2457 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2458 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2459
2460 /*
2461 * Validations.
2462 */
2463 Assert(iInstance == 0);
2464 if (!CFGMR3AreValuesValid(pCfg,
2465 "IRQ\0"
2466 "DMA\0"
2467 "DMA16\0"
2468 "Port\0"
2469 "Version\0"
2470 "TimerHz\0"))
2471 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2472 N_("Invalid configuration for SB16 device"));
2473
2474 /*
2475 * Read config data.
2476 */
2477 int rc = CFGMR3QuerySIntDef(pCfg, "IRQ", &pThis->irq, 5);
2478 if (RT_FAILURE(rc))
2479 return PDMDEV_SET_ERROR(pDevIns, rc,
2480 N_("SB16 configuration error: Failed to get the \"IRQ\" value"));
2481 pThis->irqCfg = pThis->irq;
2482
2483 rc = CFGMR3QuerySIntDef(pCfg, "DMA", &pThis->dma, 1);
2484 if (RT_FAILURE(rc))
2485 return PDMDEV_SET_ERROR(pDevIns, rc,
2486 N_("SB16 configuration error: Failed to get the \"DMA\" value"));
2487 pThis->dmaCfg = pThis->dma;
2488
2489 rc = CFGMR3QuerySIntDef(pCfg, "DMA16", &pThis->hdma, 5);
2490 if (RT_FAILURE(rc))
2491 return PDMDEV_SET_ERROR(pDevIns, rc,
2492 N_("SB16 configuration error: Failed to get the \"DMA16\" value"));
2493 pThis->hdmaCfg = pThis->hdma;
2494
2495 RTIOPORT Port;
2496 rc = CFGMR3QueryPortDef(pCfg, "Port", &Port, 0x220);
2497 if (RT_FAILURE(rc))
2498 return PDMDEV_SET_ERROR(pDevIns, rc,
2499 N_("SB16 configuration error: Failed to get the \"Port\" value"));
2500 pThis->port = Port;
2501 pThis->portCfg = Port;
2502
2503 uint16_t u16Version;
2504 rc = CFGMR3QueryU16Def(pCfg, "Version", &u16Version, 0x0405);
2505 if (RT_FAILURE(rc))
2506 return PDMDEV_SET_ERROR(pDevIns, rc,
2507 N_("SB16 configuration error: Failed to get the \"Version\" value"));
2508
2509#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
2510 uint16_t uTimerHz;
2511 rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 100 /* Hz */);
2512 if (RT_FAILURE(rc))
2513 return PDMDEV_SET_ERROR(pDevIns, rc,
2514 N_("SB16 configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
2515#endif
2516
2517 pThis->ver = u16Version;
2518 pThis->verCfg = u16Version;
2519
2520 /*
2521 * Init instance data.
2522 */
2523 pThis->pDevInsR3 = pDevIns;
2524 pThis->IBase.pfnQueryInterface = sb16QueryInterface;
2525 pThis->cmd = -1;
2526
2527 pThis->mixer_regs[0x80] = magic_of_irq (pThis->irq);
2528 pThis->mixer_regs[0x81] = (1 << pThis->dma) | (1 << pThis->hdma);
2529 pThis->mixer_regs[0x82] = 2 << 5;
2530
2531 pThis->csp_regs[5] = 1;
2532 pThis->csp_regs[9] = 0xf8;
2533
2534 RTListInit(&pThis->lstDrv);
2535
2536 sb16MixerReset(pThis);
2537
2538 /*
2539 * Create timer(s), register & attach stuff.
2540 */
2541 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIRQ, pThis,
2542 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IRQ timer", &pThis->pTimerIRQ);
2543 if (RT_FAILURE(rc))
2544 AssertMsgFailedReturn(("Error creating IRQ timer, rc=%Rrc\n", rc), rc);
2545
2546 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x04, 2, pThis,
2547 mixer_write, mixer_read, NULL, NULL, "SB16");
2548 if (RT_FAILURE(rc))
2549 return rc;
2550 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x06, 10, pThis,
2551 dsp_write, dsp_read, NULL, NULL, "SB16");
2552 if (RT_FAILURE(rc))
2553 return rc;
2554
2555 rc = PDMDevHlpDMARegister(pDevIns, pThis->hdma, sb16DMARead, pThis);
2556 if (RT_FAILURE(rc))
2557 return rc;
2558 rc = PDMDevHlpDMARegister(pDevIns, pThis->dma, sb16DMARead, pThis);
2559 if (RT_FAILURE(rc))
2560 return rc;
2561
2562 pThis->can_write = 1;
2563
2564 rc = PDMDevHlpSSMRegister3(pDevIns, SB16_SAVE_STATE_VERSION, sizeof(SB16STATE), sb16LiveExec, sb16SaveExec, sb16LoadExec);
2565 if (RT_FAILURE(rc))
2566 return rc;
2567
2568 /*
2569 * Attach driver.
2570 */
2571 uint8_t uLUN;
2572 for (uLUN = 0; uLUN < UINT8_MAX; ++uLUN)
2573 {
2574 LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
2575 rc = sb16AttachInternal(pThis, uLUN, 0 /* fFlags */, NULL /* ppDrv */);
2576 if (RT_FAILURE(rc))
2577 {
2578 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2579 rc = VINF_SUCCESS;
2580 else if (rc == VERR_AUDIO_BACKEND_INIT_FAILED)
2581 {
2582 sb16Reattach(pThis, NULL /* pDrv */, uLUN, "NullAudio");
2583 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2584 N_("Host audio backend initialization has failed. Selecting the NULL audio backend "
2585 "with the consequence that no sound is audible"));
2586 /* Attaching to the NULL audio backend will never fail. */
2587 rc = VINF_SUCCESS;
2588 }
2589 break;
2590 }
2591 }
2592
2593 LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
2594
2595 sb16ResetLegacy(pThis);
2596
2597#ifdef VBOX_WITH_AUDIO_SB16_ONETIME_INIT
2598 PSB16DRIVER pDrv;
2599 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2600 {
2601 /*
2602 * Only primary drivers are critical for the VM to run. Everything else
2603 * might not worth showing an own error message box in the GUI.
2604 */
2605 if (!(pDrv->fFlags & PDMAUDIODRVFLAGS_PRIMARY))
2606 continue;
2607
2608 PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
2609 AssertPtr(pCon);
2610
2611 /** @todo No input streams available for SB16 yet. */
2612 bool fValidOut = pCon->pfnStreamGetStatus(pCon, pDrv->Out.pStream) & PDMAUDIOSTREAMSTS_FLAG_INITIALIZED;
2613 if (!fValidOut)
2614 {
2615 LogRel(("SB16: Falling back to NULL backend (no sound audible)\n"));
2616
2617 sb16ResetLegacy(pThis);
2618 sb16Reattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
2619
2620 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2621 N_("No audio devices could be opened. Selecting the NULL audio backend "
2622 "with the consequence that no sound is audible"));
2623 }
2624 }
2625#endif
2626
2627#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
2628 if (RT_SUCCESS(rc))
2629 {
2630 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIO, pThis,
2631 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IO timer", &pThis->pTimerIO);
2632 if (RT_SUCCESS(rc))
2633 {
2634 pThis->cTimerTicksIO = TMTimerGetFreq(pThis->pTimerIO) / uTimerHz;
2635 pThis->uTimerTSIO = TMTimerGet(pThis->pTimerIO);
2636 LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicksIO, uTimerHz));
2637 }
2638 else
2639 AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
2640 }
2641#else /* !VBOX_WITH_AUDIO_SB16_CALLBACKS */
2642 if (RT_SUCCESS(rc))
2643 {
2644 /** @todo Merge this callback registration with the validation block above once
2645 * this becomes the standard. */
2646 PSB16DRIVER pDrv;
2647 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2648 {
2649 /* Only register primary driver.
2650 * The device emulation does the output multiplexing then. */
2651 if (pDrv->fFlags != PDMAUDIODRVFLAGS_PRIMARY)
2652 continue;
2653
2654 PDMAUDIOCBRECORD AudioCallbacks[2];
2655
2656 SB16CALLBACKCTX Ctx = { pThis, pDrv };
2657
2658 AudioCallbacks[0].enmType = PDMAUDIOCALLBACKTYPE_INPUT;
2659 AudioCallbacks[0].pfnCallback = sb16CallbackInput;
2660 AudioCallbacks[0].pvCtx = &Ctx;
2661 AudioCallbacks[0].cbCtx = sizeof(SB16CALLBACKCTX);
2662
2663 AudioCallbacks[1].enmType = PDMAUDIOCALLBACKTYPE_OUTPUT;
2664 AudioCallbacks[1].pfnCallback = sb16CallbackOutput;
2665 AudioCallbacks[1].pvCtx = &Ctx;
2666 AudioCallbacks[1].cbCtx = sizeof(SB16CALLBACKCTX);
2667
2668 rc = pDrv->pConnector->pfnRegisterCallbacks(pDrv->pConnector, AudioCallbacks, RT_ELEMENTS(AudioCallbacks));
2669 if (RT_FAILURE(rc))
2670 break;
2671 }
2672 }
2673#endif /* VBOX_WITH_AUDIO_SB16_CALLBACKS */
2674
2675#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
2676 RTFileDelete(VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "sb16WriteAudio.pcm");
2677#endif
2678
2679 return VINF_SUCCESS;
2680}
2681
2682const PDMDEVREG g_DeviceSB16 =
2683{
2684 /* u32Version */
2685 PDM_DEVREG_VERSION,
2686 /* szName */
2687 "sb16",
2688 /* szRCMod */
2689 "",
2690 /* szR0Mod */
2691 "",
2692 /* pszDescription */
2693 "Sound Blaster 16 Controller",
2694 /* fFlags */
2695 PDM_DEVREG_FLAGS_DEFAULT_BITS,
2696 /* fClass */
2697 PDM_DEVREG_CLASS_AUDIO,
2698 /* cMaxInstances */
2699 1,
2700 /* cbInstance */
2701 sizeof(SB16STATE),
2702 /* pfnConstruct */
2703 sb16Construct,
2704 /* pfnDestruct */
2705 sb16Destruct,
2706 /* pfnRelocate */
2707 NULL,
2708 /* pfnMemSetup */
2709 NULL,
2710 /* pfnPowerOn */
2711 NULL,
2712 /* pfnReset */
2713 sb16DevReset,
2714 /* pfnSuspend */
2715 NULL,
2716 /* pfnResume */
2717 NULL,
2718 /* pfnAttach */
2719 sb16Attach,
2720 /* pfnDetach */
2721 sb16Detach,
2722 /* pfnQueryInterface */
2723 NULL,
2724 /* pfnInitComplete */
2725 NULL,
2726 /* pfnPowerOff */
2727 sb16PowerOff,
2728 /* pfnSoftReset */
2729 NULL,
2730 /* u32VersionEnd */
2731 PDM_DEVREG_VERSION
2732};
Note: See TracBrowser for help on using the repository browser.

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