VirtualBox

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

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

Audio/DevSB16.cpp: Use sb16DestroyDrvStream() in sb16PowerOff() to avoid code duplication and disable the stream before destroying it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 84.5 KB
Line 
1/* $Id: DevSB16.cpp 70903 2018-02-08 10:07:07Z 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
1216/**
1217 * Returns the device's current master volume.
1218 *
1219 * @param pThis SB16 state.
1220 * @param pVol Where to store the master volume information.
1221 */
1222static void sb16GetMasterVolume(PSB16STATE pThis, PPDMAUDIOVOLUME pVol)
1223{
1224 /* There's no mute switch, only volume controls. */
1225 uint8_t lvol = sb16MixRegToVol(pThis, 0x30);
1226 uint8_t rvol = sb16MixRegToVol(pThis, 0x31);
1227
1228 pVol->fMuted = false;
1229 pVol->uLeft = lvol;
1230 pVol->uRight = rvol;
1231}
1232
1233/**
1234 * Returns the device's current output stream volume.
1235 *
1236 * @param pThis SB16 state.
1237 * @param pVol Where to store the output stream volume information.
1238 */
1239static void sb16GetPcmOutVolume(PSB16STATE pThis, PPDMAUDIOVOLUME pVol)
1240{
1241 /* There's no mute switch, only volume controls. */
1242 uint8_t lvol = sb16MixRegToVol(pThis, 0x32);
1243 uint8_t rvol = sb16MixRegToVol(pThis, 0x33);
1244
1245 pVol->fMuted = false;
1246 pVol->uLeft = lvol;
1247 pVol->uRight = rvol;
1248}
1249
1250static void sb16UpdateVolume(PSB16STATE pThis)
1251{
1252 PDMAUDIOVOLUME VolMaster;
1253 sb16GetMasterVolume(pThis, &VolMaster);
1254
1255 PDMAUDIOVOLUME VolOut;
1256 sb16GetPcmOutVolume(pThis, &VolOut);
1257
1258 /* Combine the master + output stream volume. */
1259 PDMAUDIOVOLUME VolCombined;
1260 RT_ZERO(VolCombined);
1261
1262 VolCombined.fMuted = VolMaster.fMuted || VolOut.fMuted;
1263 if (!VolCombined.fMuted)
1264 {
1265 VolCombined.uLeft = ( (VolOut.uLeft ? VolOut.uLeft : 1)
1266 * (VolMaster.uLeft ? VolMaster.uLeft : 1)) / PDMAUDIO_VOLUME_MAX;
1267
1268 VolCombined.uRight = ( (VolOut.uRight ? VolOut.uRight : 1)
1269 * (VolMaster.uRight ? VolMaster.uRight : 1)) / PDMAUDIO_VOLUME_MAX;
1270 }
1271
1272 PSB16DRIVER pDrv;
1273 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1274 {
1275 if (!pDrv->Out.pStream)
1276 continue;
1277
1278 int rc2 = pDrv->pConnector->pfnStreamSetVolume(pDrv->pConnector, pDrv->Out.pStream, &VolCombined);
1279 AssertRC(rc2);
1280 }
1281}
1282
1283static void sb16ResetLegacy(PSB16STATE pThis)
1284{
1285 LogFlowFuncEnter();
1286
1287 sb16CloseOut(pThis);
1288
1289 pThis->freq = 11025;
1290 pThis->fmt_signed = 0;
1291 pThis->fmt_bits = 8;
1292 pThis->fmt_stereo = 0;
1293
1294 /* At the moment we only have one stream, the output stream. */
1295 PPDMAUDIOSTREAMCFG pCfg = &pThis->Out.Cfg;
1296
1297 pCfg->enmDir = PDMAUDIODIR_OUT;
1298 pCfg->DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
1299 pCfg->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
1300
1301 pCfg->Props.uHz = pThis->freq;
1302 pCfg->Props.cChannels = 1; /* Mono */
1303 pCfg->Props.cBits = 8;
1304 pCfg->Props.fSigned = false;
1305 pCfg->Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cBits, pCfg->Props.cChannels);
1306
1307 RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "Output");
1308
1309 sb16CloseOut(pThis);
1310
1311 int rc2 = sb16OpenOut(pThis, pCfg);
1312 AssertRC(rc2);
1313}
1314
1315static void sb16Reset(PSB16STATE pThis)
1316{
1317 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
1318 if (pThis->dma_auto)
1319 {
1320 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
1321 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
1322 }
1323
1324 pThis->mixer_regs[0x82] = 0;
1325 pThis->dma_auto = 0;
1326 pThis->in_index = 0;
1327 pThis->out_data_len = 0;
1328 pThis->left_till_irq = 0;
1329 pThis->needed_bytes = 0;
1330 pThis->block_size = -1;
1331 pThis->nzero = 0;
1332 pThis->highspeed = 0;
1333 pThis->v2x6 = 0;
1334 pThis->cmd = -1;
1335
1336 dsp_out_data(pThis, 0xaa);
1337 sb16SpeakerControl(pThis, 0);
1338
1339 sb16Control(pThis, 0);
1340 sb16ResetLegacy(pThis);
1341}
1342
1343static IO_WRITE_PROTO(dsp_write)
1344{
1345 RT_NOREF(pDevIns, cb);
1346 PSB16STATE pThis = (PSB16STATE)opaque;
1347 int iport = nport - pThis->port;
1348
1349 LogFlowFunc(("write %#x <- %#x\n", nport, val));
1350 switch (iport)
1351 {
1352 case 0x06:
1353 switch (val)
1354 {
1355 case 0x00:
1356 {
1357 if (pThis->v2x6 == 1)
1358 {
1359 if (0 && pThis->highspeed)
1360 {
1361 pThis->highspeed = 0;
1362 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
1363 sb16Control(pThis, 0);
1364 }
1365 else
1366 sb16Reset(pThis);
1367 }
1368 pThis->v2x6 = 0;
1369 break;
1370 }
1371
1372 case 0x01:
1373 case 0x03: /* FreeBSD kludge */
1374 pThis->v2x6 = 1;
1375 break;
1376
1377 case 0xc6:
1378 pThis->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */
1379 break;
1380
1381 case 0xb8: /* Panic */
1382 sb16Reset(pThis);
1383 break;
1384
1385 case 0x39:
1386 dsp_out_data(pThis, 0x38);
1387 sb16Reset(pThis);
1388 pThis->v2x6 = 0x39;
1389 break;
1390
1391 default:
1392 pThis->v2x6 = val;
1393 break;
1394 }
1395 break;
1396
1397 case 0x0c: /* Write data or command | write status */
1398#if 0
1399 if (pThis->highspeed)
1400 break;
1401#endif
1402 if (0 == pThis->needed_bytes)
1403 {
1404 sb16HandleCommand(pThis, val);
1405#if 0
1406 if (0 == pThis->needed_bytes) {
1407 log_dsp (pThis);
1408 }
1409#endif
1410 }
1411 else
1412 {
1413 if (pThis->in_index == sizeof (pThis->in2_data))
1414 {
1415 LogFlowFunc(("in data overrun\n"));
1416 }
1417 else
1418 {
1419 pThis->in2_data[pThis->in_index++] = val;
1420 if (pThis->in_index == pThis->needed_bytes)
1421 {
1422 pThis->needed_bytes = 0;
1423 complete (pThis);
1424#if 0
1425 log_dsp (pThis);
1426#endif
1427 }
1428 }
1429 }
1430 break;
1431
1432 default:
1433 LogFlowFunc(("nport=%#x, val=%#x)\n", nport, val));
1434 break;
1435 }
1436
1437 return VINF_SUCCESS;
1438}
1439
1440static IO_READ_PROTO(dsp_read)
1441{
1442 RT_NOREF(pDevIns, cb);
1443 PSB16STATE pThis = (PSB16STATE)opaque;
1444 int iport, retval, ack = 0;
1445
1446 iport = nport - pThis->port;
1447
1448 /** @todo reject non-byte access?
1449 * The spec does not mention a non-byte access so we should check how real hardware behaves. */
1450
1451 switch (iport)
1452 {
1453 case 0x06: /* reset */
1454 retval = 0xff;
1455 break;
1456
1457 case 0x0a: /* read data */
1458 if (pThis->out_data_len)
1459 {
1460 retval = pThis->out_data[--pThis->out_data_len];
1461 pThis->last_read_byte = retval;
1462 }
1463 else
1464 {
1465 if (pThis->cmd != -1)
1466 LogFlowFunc(("empty output buffer for command %#x\n", pThis->cmd));
1467 retval = pThis->last_read_byte;
1468 /* goto error; */
1469 }
1470 break;
1471
1472 case 0x0c: /* 0 can write */
1473 retval = pThis->can_write ? 0 : 0x80;
1474 break;
1475
1476 case 0x0d: /* timer interrupt clear */
1477 /* LogFlowFunc(("timer interrupt clear\n")); */
1478 retval = 0;
1479 break;
1480
1481 case 0x0e: /* data available status | irq 8 ack */
1482 retval = (!pThis->out_data_len || pThis->highspeed) ? 0 : 0x80;
1483 if (pThis->mixer_regs[0x82] & 1)
1484 {
1485 ack = 1;
1486 pThis->mixer_regs[0x82] &= ~1;
1487 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
1488 }
1489 break;
1490
1491 case 0x0f: /* irq 16 ack */
1492 retval = 0xff;
1493 if (pThis->mixer_regs[0x82] & 2)
1494 {
1495 ack = 1;
1496 pThis->mixer_regs[0x82] &= ~2;
1497 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
1498 }
1499 break;
1500
1501 default:
1502 goto error;
1503 }
1504
1505 if (!ack)
1506 LogFlowFunc(("read %#x -> %#x\n", nport, retval));
1507
1508 *pu32 = retval;
1509 return VINF_SUCCESS;
1510
1511 error:
1512 LogFlowFunc(("warning: dsp_read %#x error\n", nport));
1513 return VERR_IOM_IOPORT_UNUSED;
1514}
1515
1516static void sb16MixerReset(PSB16STATE pThis)
1517{
1518 memset(pThis->mixer_regs, 0xff, 0x7f);
1519 memset(pThis->mixer_regs + 0x83, 0xff, sizeof (pThis->mixer_regs) - 0x83);
1520
1521 pThis->mixer_regs[0x02] = 4; /* master volume 3bits */
1522 pThis->mixer_regs[0x06] = 4; /* MIDI volume 3bits */
1523 pThis->mixer_regs[0x08] = 0; /* CD volume 3bits */
1524 pThis->mixer_regs[0x0a] = 0; /* voice volume 2bits */
1525
1526 /* d5=input filt, d3=lowpass filt, d1,d2=input source */
1527 pThis->mixer_regs[0x0c] = 0;
1528
1529 /* d5=output filt, d1=stereo switch */
1530 pThis->mixer_regs[0x0e] = 0;
1531
1532 /* voice volume L d5,d7, R d1,d3 */
1533 pThis->mixer_regs[0x04] = (12 << 4) | 12;
1534 /* master ... */
1535 pThis->mixer_regs[0x22] = (12 << 4) | 12;
1536 /* MIDI ... */
1537 pThis->mixer_regs[0x26] = (12 << 4) | 12;
1538
1539 /* master/voice/MIDI L/R volume */
1540 for (int i = 0x30; i < 0x36; i++)
1541 pThis->mixer_regs[i] = 24 << 3; /* -14 dB */
1542
1543 /* treble/bass */
1544 for (int i = 0x44; i < 0x48; i++)
1545 pThis->mixer_regs[i] = 0x80;
1546
1547 /* Update the master (mixer) and PCM out volumes. */
1548 sb16UpdateVolume(pThis);
1549}
1550
1551static IO_WRITE_PROTO(mixer_write_indexb)
1552{
1553 RT_NOREF(pDevIns, cb);
1554 PSB16STATE pThis = (PSB16STATE)opaque;
1555 (void) nport;
1556 pThis->mixer_nreg = val;
1557
1558 return VINF_SUCCESS;
1559}
1560
1561uint32_t popcount(uint32_t u) /** @todo r=andy WTF? */
1562{
1563 u = ((u&0x55555555) + ((u>>1)&0x55555555));
1564 u = ((u&0x33333333) + ((u>>2)&0x33333333));
1565 u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
1566 u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
1567 u = ( u&0x0000ffff) + (u>>16);
1568 return u;
1569}
1570
1571uint32_t lsbindex(uint32_t u)
1572{
1573 return popcount((u & -(int32_t)u) - 1);
1574}
1575
1576/* Convert SB16 to SB Pro mixer volume (left). */
1577static inline void sb16ConvVolumeL(PSB16STATE pThis, unsigned reg, uint8_t val)
1578{
1579 /* High nibble in SBP mixer. */
1580 pThis->mixer_regs[reg] = (pThis->mixer_regs[reg] & 0x0f) | (val & 0xf0);
1581}
1582
1583/* Convert SB16 to SB Pro mixer volume (right). */
1584static inline void sb16ConvVolumeR(PSB16STATE pThis, unsigned reg, uint8_t val)
1585{
1586 /* Low nibble in SBP mixer. */
1587 pThis->mixer_regs[reg] = (pThis->mixer_regs[reg] & 0xf0) | (val >> 4);
1588}
1589
1590/* Convert SB Pro to SB16 mixer volume (left + right). */
1591static inline void sb16ConvVolumeOldToNew(PSB16STATE pThis, unsigned reg, uint8_t val)
1592{
1593 /* Left channel. */
1594 pThis->mixer_regs[reg + 0] = (val & 0xf0) | RT_BIT(3);
1595 /* Right channel (the register immediately following). */
1596 pThis->mixer_regs[reg + 1] = (val << 4) | RT_BIT(3);
1597}
1598
1599static IO_WRITE_PROTO(mixer_write_datab)
1600{
1601 RT_NOREF(pDevIns, cb);
1602 PSB16STATE pThis = (PSB16STATE)opaque;
1603 bool fUpdateMaster = false;
1604 bool fUpdateStream = false;
1605
1606 (void) nport;
1607 LogFlowFunc(("mixer_write [%#x] <- %#x\n", pThis->mixer_nreg, val));
1608
1609 switch (pThis->mixer_nreg)
1610 {
1611 case 0x00:
1612 sb16MixerReset(pThis);
1613 /* And update the actual volume, too. */
1614 fUpdateMaster = true;
1615 fUpdateStream = true;
1616 break;
1617
1618 case 0x04: /* Translate from old style voice volume (L/R). */
1619 sb16ConvVolumeOldToNew(pThis, 0x32, val);
1620 fUpdateStream = true;
1621 break;
1622
1623 case 0x22: /* Translate from old style master volume (L/R). */
1624 sb16ConvVolumeOldToNew(pThis, 0x30, val);
1625 fUpdateMaster = true;
1626 break;
1627
1628 case 0x26: /* Translate from old style MIDI volume (L/R). */
1629 sb16ConvVolumeOldToNew(pThis, 0x34, val);
1630 break;
1631
1632 case 0x28: /* Translate from old style CD volume (L/R). */
1633 sb16ConvVolumeOldToNew(pThis, 0x36, val);
1634 break;
1635
1636 case 0x2E: /* Translate from old style line volume (L/R). */
1637 sb16ConvVolumeOldToNew(pThis, 0x38, val);
1638 break;
1639
1640 case 0x30: /* Translate to old style master volume (L). */
1641 sb16ConvVolumeL(pThis, 0x22, val);
1642 fUpdateMaster = true;
1643 break;
1644
1645 case 0x31: /* Translate to old style master volume (R). */
1646 sb16ConvVolumeR(pThis, 0x22, val);
1647 fUpdateMaster = true;
1648 break;
1649
1650 case 0x32: /* Translate to old style voice volume (L). */
1651 sb16ConvVolumeL(pThis, 0x04, val);
1652 fUpdateStream = true;
1653 break;
1654
1655 case 0x33: /* Translate to old style voice volume (R). */
1656 sb16ConvVolumeR(pThis, 0x04, val);
1657 fUpdateStream = true;
1658 break;
1659
1660 case 0x34: /* Translate to old style MIDI volume (L). */
1661 sb16ConvVolumeL(pThis, 0x26, val);
1662 break;
1663
1664 case 0x35: /* Translate to old style MIDI volume (R). */
1665 sb16ConvVolumeR(pThis, 0x26, val);
1666 break;
1667
1668 case 0x36: /* Translate to old style CD volume (L). */
1669 sb16ConvVolumeL(pThis, 0x28, val);
1670 break;
1671
1672 case 0x37: /* Translate to old style CD volume (R). */
1673 sb16ConvVolumeR(pThis, 0x28, val);
1674 break;
1675
1676 case 0x38: /* Translate to old style line volume (L). */
1677 sb16ConvVolumeL(pThis, 0x2E, val);
1678 break;
1679
1680 case 0x39: /* Translate to old style line volume (R). */
1681 sb16ConvVolumeR(pThis, 0x2E, val);
1682 break;
1683
1684 case 0x80:
1685 {
1686 int irq = irq_of_magic(val);
1687 LogFlowFunc(("setting irq to %d (val=%#x)\n", irq, val));
1688 if (irq > 0)
1689 pThis->irq = irq;
1690 break;
1691 }
1692
1693 case 0x81:
1694 {
1695 int dma, hdma;
1696
1697 dma = lsbindex (val & 0xf);
1698 hdma = lsbindex (val & 0xf0);
1699 if (dma != pThis->dma || hdma != pThis->hdma)
1700 LogFlow(("SB16: attempt to change DMA 8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
1701 dma, pThis->dma, hdma, pThis->hdma, val));
1702#if 0
1703 pThis->dma = dma;
1704 pThis->hdma = hdma;
1705#endif
1706 break;
1707 }
1708
1709 case 0x82:
1710 LogFlowFunc(("attempt to write into IRQ status register (val=%#x)\n", val));
1711 return VINF_SUCCESS;
1712
1713 default:
1714 if (pThis->mixer_nreg >= 0x80)
1715 LogFlowFunc(("attempt to write mixer[%#x] <- %#x\n", pThis->mixer_nreg, val));
1716 break;
1717 }
1718
1719 pThis->mixer_regs[pThis->mixer_nreg] = val;
1720
1721 /* Update the master (mixer) volume. */
1722 if ( fUpdateMaster
1723 || fUpdateStream)
1724 {
1725 sb16UpdateVolume(pThis);
1726 }
1727
1728 return VINF_SUCCESS;
1729}
1730
1731static IO_WRITE_PROTO(mixer_write)
1732{
1733 PSB16STATE pThis = (PSB16STATE)opaque;
1734 int iport = nport - pThis->port;
1735 switch (cb)
1736 {
1737 case 1:
1738 switch (iport)
1739 {
1740 case 4:
1741 mixer_write_indexb (pDevIns, opaque, nport, val, 1);
1742 break;
1743 case 5:
1744 mixer_write_datab (pDevIns, opaque, nport, val, 1);
1745 break;
1746 }
1747 break;
1748 case 2:
1749 mixer_write_indexb (pDevIns, opaque, nport, val & 0xff, 1);
1750 mixer_write_datab (pDevIns, opaque, nport, (val >> 8) & 0xff, 1);
1751 break;
1752 default:
1753 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", nport, cb, val));
1754 break;
1755 }
1756 return VINF_SUCCESS;
1757}
1758
1759static IO_READ_PROTO(mixer_read)
1760{
1761 RT_NOREF(pDevIns, cb);
1762 PSB16STATE pThis = (PSB16STATE)opaque;
1763
1764 (void) nport;
1765#ifndef DEBUG_SB16_MOST
1766 if (pThis->mixer_nreg != 0x82) {
1767 LogFlowFunc(("mixer_read[%#x] -> %#x\n",
1768 pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
1769 }
1770#else
1771 LogFlowFunc(("mixer_read[%#x] -> %#x\n",
1772 pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
1773#endif
1774 *pu32 = pThis->mixer_regs[pThis->mixer_nreg];
1775 return VINF_SUCCESS;
1776}
1777
1778static int sb16WriteAudio(PSB16STATE pThis, int nchan, uint32_t dma_pos,
1779 uint32_t dma_len, int len)
1780{
1781 uint8_t tmpbuf[_4K]; /** @todo Have a buffer on the heap. */
1782 uint32_t cbToWrite = len;
1783 uint32_t cbWrittenTotal = 0;
1784
1785 while (cbToWrite)
1786 {
1787 uint32_t cbToRead = RT_MIN(dma_len - dma_pos, cbToWrite);
1788 if (cbToRead > sizeof(tmpbuf))
1789 cbToRead = sizeof(tmpbuf);
1790
1791 uint32_t cbRead = 0;
1792 int rc2 = PDMDevHlpDMAReadMemory(pThis->pDevInsR3, nchan, tmpbuf, dma_pos, cbToRead, &cbRead);
1793 AssertMsgRC(rc2, (" from DMA failed: %Rrc\n", rc2));
1794
1795#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
1796 if (cbRead)
1797 {
1798 RTFILE fh;
1799 RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "sb16WriteAudio.pcm",
1800 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1801 RTFileWrite(fh, tmpbuf, cbRead, NULL);
1802 RTFileClose(fh);
1803 }
1804#endif
1805 /*
1806 * Write data to the backends.
1807 */
1808 uint32_t cbWritten = 0;
1809
1810 /* Just multiplex the output to the connected backends.
1811 * No need to utilize the virtual mixer here (yet). */
1812 PSB16DRIVER pDrv;
1813 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1814 {
1815 if (!pDrv->Out.pStream)
1816 continue;
1817
1818 uint32_t cbWrittenToStream = 0;
1819 rc2 = pDrv->pConnector->pfnStreamWrite(pDrv->pConnector, pDrv->Out.pStream, tmpbuf, cbRead, &cbWrittenToStream);
1820
1821 LogFlowFunc(("\tLUN#%RU8: rc=%Rrc, cbWrittenToStream=%RU32\n", pDrv->uLUN, rc2, cbWrittenToStream));
1822
1823 /* The primary driver sets the overall pace. */
1824 if (pDrv->fFlags & PDMAUDIODRVFLAGS_PRIMARY)
1825 {
1826 cbWritten = cbWrittenToStream;
1827
1828 if (RT_FAILURE(rc2))
1829 break;
1830 }
1831 }
1832
1833 LogFlowFunc(("\tcbToRead=%RU32, cbToWrite=%RU32, cbWritten=%RU32, cbLeft=%RU32\n",
1834 cbToRead, cbToWrite, cbWritten, cbToWrite - cbWrittenTotal));
1835
1836 Assert(cbToWrite >= cbWritten);
1837 cbToWrite -= cbWritten;
1838 dma_pos = (dma_pos + cbWritten) % dma_len;
1839 cbWrittenTotal += cbWritten;
1840
1841 if (!cbWritten)
1842 break;
1843 }
1844
1845 return cbWrittenTotal;
1846}
1847
1848static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
1849{
1850 RT_NOREF(pDevIns);
1851 PSB16STATE pThis = (PSB16STATE)opaque;
1852 int till, copy, written, free;
1853
1854 if (pThis->block_size <= 0)
1855 {
1856 LogFlowFunc(("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
1857 pThis->block_size, nchan, dma_pos, dma_len));
1858 return dma_pos;
1859 }
1860
1861 if (pThis->left_till_irq < 0)
1862 pThis->left_till_irq = pThis->block_size;
1863
1864 uint32_t cbOutMin = UINT32_MAX;
1865
1866 PSB16DRIVER pDrv;
1867 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1868 {
1869 if (!pDrv->Out.pStream)
1870 continue;
1871
1872 uint32_t cbOut = pDrv->pConnector->pfnStreamGetWritable(pDrv->pConnector, pDrv->Out.pStream);
1873
1874 if (cbOut < cbOutMin)
1875 cbOutMin = cbOut;
1876 }
1877
1878 LogFlowFunc(("cbOutMin=%RU32\n", cbOutMin));
1879 if (cbOutMin == UINT32_MAX)
1880 {
1881 free = dma_len;
1882 }
1883 else
1884 {
1885 free = cbOutMin & ~pThis->align; /** @todo int vs. uint32. */
1886 if ((free <= 0) || !dma_len)
1887 return dma_pos;
1888 }
1889
1890 copy = free;
1891 till = pThis->left_till_irq;
1892
1893#ifdef DEBUG_SB16_MOST
1894 LogFlowFunc(("pos:%06d %d till:%d len:%d\n", dma_pos, free, till, dma_len));
1895#endif
1896
1897 if (copy >= till)
1898 {
1899 if (0 == pThis->dma_auto)
1900 {
1901 copy = till;
1902 }
1903 else
1904 {
1905 if (copy >= till + pThis->block_size)
1906 copy = till; /* Make sure we won't skip IRQs. */
1907 }
1908 }
1909
1910 written = sb16WriteAudio(pThis, nchan, dma_pos, dma_len, copy);
1911 dma_pos = (dma_pos + written) % dma_len;
1912 pThis->left_till_irq -= written;
1913
1914 if (pThis->left_till_irq <= 0)
1915 {
1916 pThis->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
1917 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
1918 if (0 == pThis->dma_auto)
1919 {
1920 sb16Control(pThis, 0);
1921 sb16SpeakerControl(pThis, 0);
1922 }
1923 }
1924
1925 Log3Func(("pos %d/%d free %5d till %5d copy %5d written %5d block_size %5d\n",
1926 dma_pos, dma_len, free, pThis->left_till_irq, copy, written,
1927 pThis->block_size));
1928
1929 while (pThis->left_till_irq <= 0)
1930 pThis->left_till_irq += pThis->block_size;
1931
1932 return dma_pos;
1933}
1934
1935#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
1936static void sb16TimerMaybeStart(PSB16STATE pThis)
1937{
1938 LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
1939
1940 if (pThis->cStreamsActive == 0) /* Only start the timer if there are no active streams. */
1941 return;
1942
1943 if (!pThis->pTimerIO)
1944 return;
1945
1946 /* Set timer flag. */
1947 ASMAtomicXchgBool(&pThis->fTimerActive, true);
1948
1949 /* Update current time timestamp. */
1950 pThis->uTimerTSIO = TMTimerGet(pThis->pTimerIO);
1951
1952 /* Fire off timer. */
1953 TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->cTimerTicksIO);
1954}
1955
1956static void sb16TimerMaybeStop(PSB16STATE pThis)
1957{
1958 LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
1959
1960 if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
1961 return;
1962
1963 if (!pThis->pTimerIO)
1964 return;
1965
1966 /* Set timer flag. */
1967 ASMAtomicXchgBool(&pThis->fTimerActive, false);
1968}
1969
1970static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1971{
1972 RT_NOREF(pDevIns);
1973 PSB16STATE pThis = (PSB16STATE)pvUser;
1974 Assert(pThis == PDMINS_2_DATA(pDevIns, PSB16STATE));
1975 AssertPtr(pThis);
1976
1977 uint64_t cTicksNow = TMTimerGet(pTimer);
1978 bool fIsPlaying = false; /* Whether one or more streams are still playing. */
1979 bool fDoTransfer = false;
1980
1981 pThis->uTimerTSIO = cTicksNow;
1982
1983 PSB16DRIVER pDrv;
1984 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1985 {
1986 PPDMAUDIOSTREAM pStream = pDrv->Out.pStream;
1987 if (!pStream)
1988 continue;
1989
1990#ifdef VBOX_STRICT
1991 /*
1992 * Sanity. Make sure that all streams have the same configuration
1993 * to get SB16's DMA transfers right.
1994 *
1995 * SB16 only allows one output configuration per serial data out,
1996 * so check if all streams have the same configuration.
1997 */
1998 PSB16DRIVER pDrvPrev = RTListNodeGetPrev(&pDrv->Node, SB16DRIVER, Node);
1999 if ( pDrvPrev
2000 && !RTListNodeIsDummy(&pThis->lstDrv, pDrvPrev, SB16DRIVER, Node))
2001 {
2002 PPDMAUDIOSTREAM pStreamPrev = pDrvPrev->Out.pStream;
2003 if (pStreamPrev)
2004 {
2005 AssertMsg(pStream->Cfg.Props.uHz == pStreamPrev->Cfg.Props.uHz,
2006 ("%RU32Hz vs. %RU32Hz\n", pStream->Cfg.Props.uHz, pStreamPrev->Cfg.Props.uHz));
2007 AssertMsg(pStream->Cfg.Props.cChannels == pStreamPrev->Cfg.Props.cChannels,
2008 ("%RU8 vs. %RU8 channels\n", pStream->Cfg.Props.cChannels, pStreamPrev->Cfg.Props.cChannels));
2009 AssertMsg(pStream->Cfg.Props.cBits == pStreamPrev->Cfg.Props.cBits,
2010 ("%d vs. %d bits\n", pStream->Cfg.Props.cBits, pStreamPrev->Cfg.Props.cBits));
2011 AssertMsg(pStream->Cfg.Props.fSigned == pStreamPrev->Cfg.Props.fSigned,
2012 ("%RTbool vs. %RTbool signed\n", pStream->Cfg.Props.fSigned, pStreamPrev->Cfg.Props.fSigned));
2013 }
2014 }
2015#endif
2016 PPDMIAUDIOCONNECTOR pConn = pDrv->pConnector;
2017 if (!pConn)
2018 continue;
2019
2020 int rc2 = pConn->pfnStreamIterate(pConn, pStream);
2021 if (RT_SUCCESS(rc2))
2022 {
2023 if (pStream->enmDir == PDMAUDIODIR_IN)
2024 {
2025 /** @todo Implement recording! */
2026 }
2027 else
2028 {
2029 rc2 = pConn->pfnStreamPlay(pConn, pStream, NULL /* cPlayed */);
2030 if (RT_FAILURE(rc2))
2031 {
2032 LogFlowFunc(("%s: Failed playing stream, rc=%Rrc\n", pStream->szName, rc2));
2033 continue;
2034 }
2035 }
2036
2037 if (pDrv->fFlags & PDMAUDIODRVFLAGS_PRIMARY)
2038 {
2039 /* Only do the next DMA transfer if we're able to write the remaining data block. */
2040 fDoTransfer = pConn->pfnStreamGetWritable(pConn, pStream) > (unsigned)pThis->left_till_irq;
2041 }
2042 }
2043
2044 PDMAUDIOSTREAMSTS strmSts = pConn->pfnStreamGetStatus(pConn, pStream);
2045 fIsPlaying |= ( (strmSts & PDMAUDIOSTREAMSTS_FLAG_ENABLED)
2046 || (strmSts & PDMAUDIOSTREAMSTS_FLAG_PENDING_DISABLE));
2047 }
2048
2049 bool fTimerActive = ASMAtomicReadBool(&pThis->fTimerActive);
2050 bool fKickTimer = fTimerActive || fIsPlaying;
2051
2052 LogFlowFunc(("fTimerActive=%RTbool, fIsPlaying=%RTbool\n", fTimerActive, fIsPlaying));
2053
2054 if (fDoTransfer)
2055 {
2056 /* Schedule the next transfer. */
2057 PDMDevHlpDMASchedule(pThis->pDevInsR3);
2058
2059 /* Kick the timer at least one more time. */
2060 fKickTimer = true;
2061 }
2062
2063 /*
2064 * Recording.
2065 */
2066 /** @todo Implement recording. */
2067
2068 if (fKickTimer)
2069 {
2070 /* Kick the timer again. */
2071 uint64_t cTicks = pThis->cTimerTicksIO;
2072 /** @todo adjust cTicks down by now much cbOutMin represents. */
2073 TMTimerSet(pThis->pTimerIO, cTicksNow + cTicks);
2074 }
2075}
2076#endif /* !VBOX_WITH_AUDIO_SB16_CALLBACKS */
2077
2078static void sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis)
2079{
2080 SSMR3PutS32(pSSM, pThis->irq);
2081 SSMR3PutS32(pSSM, pThis->dma);
2082 SSMR3PutS32(pSSM, pThis->hdma);
2083 SSMR3PutS32(pSSM, pThis->port);
2084 SSMR3PutS32(pSSM, pThis->ver);
2085 SSMR3PutS32(pSSM, pThis->in_index);
2086 SSMR3PutS32(pSSM, pThis->out_data_len);
2087 SSMR3PutS32(pSSM, pThis->fmt_stereo);
2088 SSMR3PutS32(pSSM, pThis->fmt_signed);
2089 SSMR3PutS32(pSSM, pThis->fmt_bits);
2090
2091 SSMR3PutU32(pSSM, pThis->fmt);
2092
2093 SSMR3PutS32(pSSM, pThis->dma_auto);
2094 SSMR3PutS32(pSSM, pThis->block_size);
2095 SSMR3PutS32(pSSM, pThis->fifo);
2096 SSMR3PutS32(pSSM, pThis->freq);
2097 SSMR3PutS32(pSSM, pThis->time_const);
2098 SSMR3PutS32(pSSM, pThis->speaker);
2099 SSMR3PutS32(pSSM, pThis->needed_bytes);
2100 SSMR3PutS32(pSSM, pThis->cmd);
2101 SSMR3PutS32(pSSM, pThis->use_hdma);
2102 SSMR3PutS32(pSSM, pThis->highspeed);
2103 SSMR3PutS32(pSSM, pThis->can_write);
2104 SSMR3PutS32(pSSM, pThis->v2x6);
2105
2106 SSMR3PutU8 (pSSM, pThis->csp_param);
2107 SSMR3PutU8 (pSSM, pThis->csp_value);
2108 SSMR3PutU8 (pSSM, pThis->csp_mode);
2109 SSMR3PutU8 (pSSM, pThis->csp_param); /* Bug compatible! */
2110 SSMR3PutMem(pSSM, pThis->csp_regs, 256);
2111 SSMR3PutU8 (pSSM, pThis->csp_index);
2112 SSMR3PutMem(pSSM, pThis->csp_reg83, 4);
2113 SSMR3PutS32(pSSM, pThis->csp_reg83r);
2114 SSMR3PutS32(pSSM, pThis->csp_reg83w);
2115
2116 SSMR3PutMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
2117 SSMR3PutMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
2118 SSMR3PutU8 (pSSM, pThis->test_reg);
2119 SSMR3PutU8 (pSSM, pThis->last_read_byte);
2120
2121 SSMR3PutS32(pSSM, pThis->nzero);
2122 SSMR3PutS32(pSSM, pThis->left_till_irq);
2123 SSMR3PutS32(pSSM, pThis->dma_running);
2124 SSMR3PutS32(pSSM, pThis->bytes_per_second);
2125 SSMR3PutS32(pSSM, pThis->align);
2126
2127 SSMR3PutS32(pSSM, pThis->mixer_nreg);
2128 SSMR3PutMem(pSSM, pThis->mixer_regs, 256);
2129
2130}
2131
2132static int sb16Load(PSSMHANDLE pSSM, PSB16STATE pThis)
2133{
2134 SSMR3GetS32(pSSM, &pThis->irq);
2135 SSMR3GetS32(pSSM, &pThis->dma);
2136 SSMR3GetS32(pSSM, &pThis->hdma);
2137 SSMR3GetS32(pSSM, &pThis->port);
2138 SSMR3GetS32(pSSM, &pThis->ver);
2139 SSMR3GetS32(pSSM, &pThis->in_index);
2140 SSMR3GetS32(pSSM, &pThis->out_data_len);
2141 SSMR3GetS32(pSSM, &pThis->fmt_stereo);
2142 SSMR3GetS32(pSSM, &pThis->fmt_signed);
2143 SSMR3GetS32(pSSM, &pThis->fmt_bits);
2144
2145 SSMR3GetU32(pSSM, (uint32_t *)&pThis->fmt);
2146
2147 SSMR3GetS32(pSSM, &pThis->dma_auto);
2148 SSMR3GetS32(pSSM, &pThis->block_size);
2149 SSMR3GetS32(pSSM, &pThis->fifo);
2150 SSMR3GetS32(pSSM, &pThis->freq);
2151 SSMR3GetS32(pSSM, &pThis->time_const);
2152 SSMR3GetS32(pSSM, &pThis->speaker);
2153 SSMR3GetS32(pSSM, &pThis->needed_bytes);
2154 SSMR3GetS32(pSSM, &pThis->cmd);
2155 SSMR3GetS32(pSSM, &pThis->use_hdma);
2156 SSMR3GetS32(pSSM, &pThis->highspeed);
2157 SSMR3GetS32(pSSM, &pThis->can_write);
2158 SSMR3GetS32(pSSM, &pThis->v2x6);
2159
2160 SSMR3GetU8 (pSSM, &pThis->csp_param);
2161 SSMR3GetU8 (pSSM, &pThis->csp_value);
2162 SSMR3GetU8 (pSSM, &pThis->csp_mode);
2163 SSMR3GetU8 (pSSM, &pThis->csp_param); /* Bug compatible! */
2164 SSMR3GetMem(pSSM, pThis->csp_regs, 256);
2165 SSMR3GetU8 (pSSM, &pThis->csp_index);
2166 SSMR3GetMem(pSSM, pThis->csp_reg83, 4);
2167 SSMR3GetS32(pSSM, &pThis->csp_reg83r);
2168 SSMR3GetS32(pSSM, &pThis->csp_reg83w);
2169
2170 SSMR3GetMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
2171 SSMR3GetMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
2172 SSMR3GetU8 (pSSM, &pThis->test_reg);
2173 SSMR3GetU8 (pSSM, &pThis->last_read_byte);
2174
2175 SSMR3GetS32(pSSM, &pThis->nzero);
2176 SSMR3GetS32(pSSM, &pThis->left_till_irq);
2177 SSMR3GetS32(pSSM, &pThis->dma_running);
2178 SSMR3GetS32(pSSM, &pThis->bytes_per_second);
2179 SSMR3GetS32(pSSM, &pThis->align);
2180
2181 SSMR3GetS32(pSSM, &pThis->mixer_nreg);
2182 SSMR3GetMem(pSSM, pThis->mixer_regs, 256);
2183
2184#if 0
2185 PSB16DRIVER pDrv;
2186 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2187 {
2188 if (pDrv->Out.pStream)
2189 {
2190 pDrv->pConnector->pfnCloseOut(pThis->pDrv, pDrv->Out.pStream);
2191 pDrv->Out.pStream = NULL;
2192 }
2193 }
2194#endif
2195
2196 if (pThis->dma_running)
2197 {
2198 if (pThis->freq)
2199 {
2200 /* At the moment we only have one stream, the output stream. */
2201 PPDMAUDIOSTREAMCFG pCfg = &pThis->Out.Cfg;
2202
2203 pCfg->enmDir = PDMAUDIODIR_OUT;
2204 pCfg->DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
2205 pCfg->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
2206
2207 pCfg->Props.uHz = pThis->freq;
2208 pCfg->Props.cChannels = 1 << pThis->fmt_stereo;
2209 pCfg->Props.cBits = pThis->fmt_bits;
2210 pCfg->Props.fSigned = RT_BOOL(pThis->fmt_signed);
2211 pCfg->Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cBits, pCfg->Props.cChannels);
2212
2213 RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "Output");
2214
2215 sb16CloseOut(pThis);
2216
2217 int rc = sb16OpenOut(pThis, pCfg);
2218 AssertRC(rc);
2219 }
2220
2221 sb16Control(pThis, 1);
2222 sb16SpeakerControl(pThis, pThis->speaker);
2223 }
2224
2225 /* Update the master (mixer) and PCM out volumes. */
2226 sb16UpdateVolume(pThis);
2227
2228 return VINF_SUCCESS;
2229}
2230
2231static DECLCALLBACK(int) sb16LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
2232{
2233 RT_NOREF(uPass);
2234 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2235
2236 SSMR3PutS32(pSSM, pThis->irqCfg);
2237 SSMR3PutS32(pSSM, pThis->dmaCfg);
2238 SSMR3PutS32(pSSM, pThis->hdmaCfg);
2239 SSMR3PutS32(pSSM, pThis->portCfg);
2240 SSMR3PutS32(pSSM, pThis->verCfg);
2241 return VINF_SSM_DONT_CALL_AGAIN;
2242}
2243
2244static DECLCALLBACK(int) sb16SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2245{
2246 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2247
2248 sb16LiveExec(pDevIns, pSSM, 0);
2249 sb16Save(pSSM, pThis);
2250 return VINF_SUCCESS;
2251}
2252
2253static DECLCALLBACK(int) sb16LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2254{
2255 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2256
2257 AssertMsgReturn( uVersion == SB16_SAVE_STATE_VERSION
2258 || uVersion == SB16_SAVE_STATE_VERSION_VBOX_30,
2259 ("%u\n", uVersion),
2260 VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
2261 if (uVersion > SB16_SAVE_STATE_VERSION_VBOX_30)
2262 {
2263 int32_t irq;
2264 SSMR3GetS32 (pSSM, &irq);
2265 int32_t dma;
2266 SSMR3GetS32 (pSSM, &dma);
2267 int32_t hdma;
2268 SSMR3GetS32 (pSSM, &hdma);
2269 int32_t port;
2270 SSMR3GetS32 (pSSM, &port);
2271 int32_t ver;
2272 int rc = SSMR3GetS32 (pSSM, &ver);
2273 AssertRCReturn (rc, rc);
2274
2275 if ( irq != pThis->irqCfg
2276 || dma != pThis->dmaCfg
2277 || hdma != pThis->hdmaCfg
2278 || port != pThis->portCfg
2279 || ver != pThis->verCfg)
2280 {
2281 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
2282 N_("config changed: irq=%x/%x dma=%x/%x hdma=%x/%x port=%x/%x ver=%x/%x (saved/config)"),
2283 irq, pThis->irqCfg,
2284 dma, pThis->dmaCfg,
2285 hdma, pThis->hdmaCfg,
2286 port, pThis->portCfg,
2287 ver, pThis->verCfg);
2288 }
2289 }
2290
2291 if (uPass != SSM_PASS_FINAL)
2292 return VINF_SUCCESS;
2293
2294 sb16Load(pSSM, pThis);
2295 return VINF_SUCCESS;
2296}
2297
2298/**
2299 * Creates a PDM audio stream for a specific driver.
2300 *
2301 * @returns IPRT status code.
2302 * @param pThis SB16 state.
2303 * @param pCfg Stream configuration to use.
2304 * @param pDrv Driver stream to create PDM stream for.
2305 */
2306static int sb16CreateDrvStream(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg, PSB16DRIVER pDrv)
2307{
2308 RT_NOREF(pThis);
2309
2310 AssertReturn(pCfg->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER);
2311 Assert(DrvAudioHlpStreamCfgIsValid(pCfg));
2312
2313 PPDMAUDIOSTREAMCFG pCfgHost = DrvAudioHlpStreamCfgDup(pCfg);
2314 if (!pCfgHost)
2315 return VERR_NO_MEMORY;
2316
2317 if (!RTStrPrintf(pCfgHost->szName, sizeof(pCfgHost->szName), "%s", pCfg->szName))
2318 {
2319 RTMemFree(pCfgHost);
2320 return VERR_BUFFER_OVERFLOW;
2321 }
2322
2323 LogFunc(("[LUN#%RU8] %s\n", pDrv->uLUN, pCfgHost->szName));
2324
2325 AssertMsg(pDrv->Out.pStream == NULL, ("[LUN#%RU8] Driver stream already present when it must not\n", pDrv->uLUN));
2326
2327 int rc = pDrv->pConnector->pfnStreamCreate(pDrv->pConnector, pCfgHost, pCfg /* pCfgGuest */, &pDrv->Out.pStream);
2328 if (RT_SUCCESS(rc))
2329 {
2330 pDrv->pConnector->pfnStreamRetain(pDrv->pConnector, pDrv->Out.pStream);
2331 LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc));
2332 }
2333
2334 if (pCfgHost)
2335 {
2336 RTMemFree(pCfgHost);
2337 pCfgHost = NULL;
2338 }
2339
2340 return rc;
2341}
2342
2343/**
2344 * Destroys a PDM audio stream of a specific driver.
2345 *
2346 * @param pThis SB16 state.
2347 * @param pDrv Driver stream to destroy PDM stream for.
2348 */
2349static void sb16DestroyDrvStream(PSB16STATE pThis, PSB16DRIVER pDrv)
2350{
2351 AssertPtrReturnVoid(pThis);
2352 AssertPtrReturnVoid(pDrv);
2353
2354 if (pDrv->Out.pStream)
2355 {
2356 pDrv->pConnector->pfnStreamRelease(pDrv->pConnector, pDrv->Out.pStream);
2357
2358 int rc2 = pDrv->pConnector->pfnStreamControl(pDrv->pConnector, pDrv->Out.pStream, PDMAUDIOSTREAMCMD_DISABLE);
2359 AssertRC(rc2);
2360
2361 rc2 = pDrv->pConnector->pfnStreamDestroy(pDrv->pConnector, pDrv->Out.pStream);
2362 AssertRC(rc2);
2363
2364 pDrv->Out.pStream = NULL;
2365 }
2366}
2367
2368static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg)
2369{
2370 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2371 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2372
2373 LogFlowFuncEnter();
2374
2375 if (!DrvAudioHlpStreamCfgIsValid(pCfg))
2376 return VERR_INVALID_PARAMETER;
2377
2378 int rc = VINF_SUCCESS;
2379
2380 PSB16DRIVER pDrv;
2381 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2382 {
2383 int rc2 = sb16CreateDrvStream(pThis, pCfg, pDrv);
2384 if (RT_FAILURE(rc2))
2385 LogFunc(("Attaching stream failed with %Rrc\n", rc2));
2386
2387 /* Do not pass failure to rc here, as there might be drivers which aren't
2388 * configured / ready yet. */
2389 }
2390
2391 sb16UpdateVolume(pThis);
2392
2393 LogFlowFuncLeaveRC(rc);
2394 return rc;
2395}
2396
2397static void sb16CloseOut(PSB16STATE pThis)
2398{
2399 AssertPtrReturnVoid(pThis);
2400
2401 LogFlowFuncEnter();
2402
2403 PSB16DRIVER pDrv;
2404 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2405 sb16DestroyDrvStream(pThis, pDrv);
2406
2407 LogFlowFuncLeave();
2408}
2409
2410/**
2411 * @interface_method_impl{PDMDEVREG,pfnReset}
2412 */
2413static DECLCALLBACK(void) sb16DevReset(PPDMDEVINS pDevIns)
2414{
2415 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2416
2417 /* Bring back the device to initial state, and especially make
2418 * sure there's no interrupt or DMA activity.
2419 */
2420 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
2421
2422 pThis->mixer_regs[0x82] = 0;
2423 pThis->csp_regs[5] = 1;
2424 pThis->csp_regs[9] = 0xf8;
2425
2426 pThis->dma_auto = 0;
2427 pThis->in_index = 0;
2428 pThis->out_data_len = 0;
2429 pThis->left_till_irq = 0;
2430 pThis->needed_bytes = 0;
2431 pThis->block_size = -1;
2432 pThis->nzero = 0;
2433 pThis->highspeed = 0;
2434 pThis->v2x6 = 0;
2435 pThis->cmd = -1;
2436
2437 sb16MixerReset(pThis);
2438 sb16SpeakerControl(pThis, 0);
2439 sb16Control(pThis, 0);
2440 sb16ResetLegacy(pThis);
2441}
2442
2443/**
2444 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2445 */
2446static DECLCALLBACK(void *) sb16QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
2447{
2448 PSB16STATE pThis = RT_FROM_MEMBER(pInterface, SB16STATE, IBase);
2449 Assert(&pThis->IBase == pInterface);
2450
2451 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2452 return NULL;
2453}
2454
2455/**
2456 * Powers off the device.
2457 *
2458 * @param pDevIns Device instance to power off.
2459 */
2460static DECLCALLBACK(void) sb16PowerOff(PPDMDEVINS pDevIns)
2461{
2462 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2463
2464 LogRel2(("SB16: Powering off ...\n"));
2465
2466 PSB16DRIVER pDrv;
2467 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2468 sb16DestroyDrvStream(pThis, pDrv);
2469}
2470
2471/**
2472 * @interface_method_impl{PDMDEVREG,pfnDestruct}
2473 */
2474static DECLCALLBACK(int) sb16Destruct(PPDMDEVINS pDevIns)
2475{
2476 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2477 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2478
2479 LogFlowFuncEnter();
2480
2481 PSB16DRIVER pDrv;
2482 while (!RTListIsEmpty(&pThis->lstDrv))
2483 {
2484 pDrv = RTListGetFirst(&pThis->lstDrv, SB16DRIVER, Node);
2485
2486 RTListNodeRemove(&pDrv->Node);
2487 RTMemFree(pDrv);
2488 }
2489
2490 return VINF_SUCCESS;
2491}
2492
2493static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2494{
2495 RT_NOREF(iInstance);
2496 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2497 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2498
2499 /*
2500 * Validations.
2501 */
2502 Assert(iInstance == 0);
2503 if (!CFGMR3AreValuesValid(pCfg,
2504 "IRQ\0"
2505 "DMA\0"
2506 "DMA16\0"
2507 "Port\0"
2508 "Version\0"
2509 "TimerHz\0"))
2510 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2511 N_("Invalid configuration for SB16 device"));
2512
2513 /*
2514 * Read config data.
2515 */
2516 int rc = CFGMR3QuerySIntDef(pCfg, "IRQ", &pThis->irq, 5);
2517 if (RT_FAILURE(rc))
2518 return PDMDEV_SET_ERROR(pDevIns, rc,
2519 N_("SB16 configuration error: Failed to get the \"IRQ\" value"));
2520 pThis->irqCfg = pThis->irq;
2521
2522 rc = CFGMR3QuerySIntDef(pCfg, "DMA", &pThis->dma, 1);
2523 if (RT_FAILURE(rc))
2524 return PDMDEV_SET_ERROR(pDevIns, rc,
2525 N_("SB16 configuration error: Failed to get the \"DMA\" value"));
2526 pThis->dmaCfg = pThis->dma;
2527
2528 rc = CFGMR3QuerySIntDef(pCfg, "DMA16", &pThis->hdma, 5);
2529 if (RT_FAILURE(rc))
2530 return PDMDEV_SET_ERROR(pDevIns, rc,
2531 N_("SB16 configuration error: Failed to get the \"DMA16\" value"));
2532 pThis->hdmaCfg = pThis->hdma;
2533
2534 RTIOPORT Port;
2535 rc = CFGMR3QueryPortDef(pCfg, "Port", &Port, 0x220);
2536 if (RT_FAILURE(rc))
2537 return PDMDEV_SET_ERROR(pDevIns, rc,
2538 N_("SB16 configuration error: Failed to get the \"Port\" value"));
2539 pThis->port = Port;
2540 pThis->portCfg = Port;
2541
2542 uint16_t u16Version;
2543 rc = CFGMR3QueryU16Def(pCfg, "Version", &u16Version, 0x0405);
2544 if (RT_FAILURE(rc))
2545 return PDMDEV_SET_ERROR(pDevIns, rc,
2546 N_("SB16 configuration error: Failed to get the \"Version\" value"));
2547
2548#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
2549 uint16_t uTimerHz;
2550 rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 100 /* Hz */);
2551 if (RT_FAILURE(rc))
2552 return PDMDEV_SET_ERROR(pDevIns, rc,
2553 N_("SB16 configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
2554#endif
2555
2556 pThis->ver = u16Version;
2557 pThis->verCfg = u16Version;
2558
2559 /*
2560 * Init instance data.
2561 */
2562 pThis->pDevInsR3 = pDevIns;
2563 pThis->IBase.pfnQueryInterface = sb16QueryInterface;
2564 pThis->cmd = -1;
2565
2566 pThis->mixer_regs[0x80] = magic_of_irq (pThis->irq);
2567 pThis->mixer_regs[0x81] = (1 << pThis->dma) | (1 << pThis->hdma);
2568 pThis->mixer_regs[0x82] = 2 << 5;
2569
2570 pThis->csp_regs[5] = 1;
2571 pThis->csp_regs[9] = 0xf8;
2572
2573 RTListInit(&pThis->lstDrv);
2574
2575 sb16MixerReset(pThis);
2576
2577 /*
2578 * Create timer(s), register & attach stuff.
2579 */
2580 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIRQ, pThis,
2581 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IRQ timer", &pThis->pTimerIRQ);
2582 if (RT_FAILURE(rc))
2583 AssertMsgFailedReturn(("Error creating IRQ timer, rc=%Rrc\n", rc), rc);
2584
2585 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x04, 2, pThis,
2586 mixer_write, mixer_read, NULL, NULL, "SB16");
2587 if (RT_FAILURE(rc))
2588 return rc;
2589 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x06, 10, pThis,
2590 dsp_write, dsp_read, NULL, NULL, "SB16");
2591 if (RT_FAILURE(rc))
2592 return rc;
2593
2594 rc = PDMDevHlpDMARegister(pDevIns, pThis->hdma, sb16DMARead, pThis);
2595 if (RT_FAILURE(rc))
2596 return rc;
2597 rc = PDMDevHlpDMARegister(pDevIns, pThis->dma, sb16DMARead, pThis);
2598 if (RT_FAILURE(rc))
2599 return rc;
2600
2601 pThis->can_write = 1;
2602
2603 rc = PDMDevHlpSSMRegister3(pDevIns, SB16_SAVE_STATE_VERSION, sizeof(SB16STATE), sb16LiveExec, sb16SaveExec, sb16LoadExec);
2604 if (RT_FAILURE(rc))
2605 return rc;
2606
2607 /*
2608 * Attach driver.
2609 */
2610 uint8_t uLUN;
2611 for (uLUN = 0; uLUN < UINT8_MAX; ++uLUN)
2612 {
2613 LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
2614 rc = sb16AttachInternal(pThis, uLUN, 0 /* fFlags */, NULL /* ppDrv */);
2615 if (RT_FAILURE(rc))
2616 {
2617 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2618 rc = VINF_SUCCESS;
2619 else if (rc == VERR_AUDIO_BACKEND_INIT_FAILED)
2620 {
2621 sb16Reattach(pThis, NULL /* pDrv */, uLUN, "NullAudio");
2622 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2623 N_("Host audio backend initialization has failed. Selecting the NULL audio backend "
2624 "with the consequence that no sound is audible"));
2625 /* Attaching to the NULL audio backend will never fail. */
2626 rc = VINF_SUCCESS;
2627 }
2628 break;
2629 }
2630 }
2631
2632 LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
2633
2634 sb16ResetLegacy(pThis);
2635
2636#ifdef VBOX_WITH_AUDIO_SB16_ONETIME_INIT
2637 PSB16DRIVER pDrv;
2638 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2639 {
2640 /*
2641 * Only primary drivers are critical for the VM to run. Everything else
2642 * might not worth showing an own error message box in the GUI.
2643 */
2644 if (!(pDrv->fFlags & PDMAUDIODRVFLAGS_PRIMARY))
2645 continue;
2646
2647 PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
2648 AssertPtr(pCon);
2649
2650 /** @todo No input streams available for SB16 yet. */
2651
2652 if (!pDrv->Out.pStream)
2653 continue;
2654
2655 bool fValidOut = pCon->pfnStreamGetStatus(pCon, pDrv->Out.pStream) & PDMAUDIOSTREAMSTS_FLAG_INITIALIZED;
2656 if (!fValidOut)
2657 {
2658 LogRel(("SB16: Falling back to NULL backend (no sound audible)\n"));
2659
2660 sb16ResetLegacy(pThis);
2661 sb16Reattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
2662
2663 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2664 N_("No audio devices could be opened. Selecting the NULL audio backend "
2665 "with the consequence that no sound is audible"));
2666 }
2667 }
2668#endif
2669
2670#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
2671 if (RT_SUCCESS(rc))
2672 {
2673 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIO, pThis,
2674 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IO timer", &pThis->pTimerIO);
2675 if (RT_SUCCESS(rc))
2676 {
2677 pThis->cTimerTicksIO = TMTimerGetFreq(pThis->pTimerIO) / uTimerHz;
2678 pThis->uTimerTSIO = TMTimerGet(pThis->pTimerIO);
2679 LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicksIO, uTimerHz));
2680 }
2681 else
2682 AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
2683 }
2684#else /* !VBOX_WITH_AUDIO_SB16_CALLBACKS */
2685 if (RT_SUCCESS(rc))
2686 {
2687 /** @todo Merge this callback registration with the validation block above once
2688 * this becomes the standard. */
2689 PSB16DRIVER pDrv;
2690 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2691 {
2692 /* Only register primary driver.
2693 * The device emulation does the output multiplexing then. */
2694 if (pDrv->fFlags != PDMAUDIODRVFLAGS_PRIMARY)
2695 continue;
2696
2697 PDMAUDIOCBRECORD AudioCallbacks[2];
2698
2699 SB16CALLBACKCTX Ctx = { pThis, pDrv };
2700
2701 AudioCallbacks[0].enmType = PDMAUDIOCALLBACKTYPE_INPUT;
2702 AudioCallbacks[0].pfnCallback = sb16CallbackInput;
2703 AudioCallbacks[0].pvCtx = &Ctx;
2704 AudioCallbacks[0].cbCtx = sizeof(SB16CALLBACKCTX);
2705
2706 AudioCallbacks[1].enmType = PDMAUDIOCALLBACKTYPE_OUTPUT;
2707 AudioCallbacks[1].pfnCallback = sb16CallbackOutput;
2708 AudioCallbacks[1].pvCtx = &Ctx;
2709 AudioCallbacks[1].cbCtx = sizeof(SB16CALLBACKCTX);
2710
2711 rc = pDrv->pConnector->pfnRegisterCallbacks(pDrv->pConnector, AudioCallbacks, RT_ELEMENTS(AudioCallbacks));
2712 if (RT_FAILURE(rc))
2713 break;
2714 }
2715 }
2716#endif /* VBOX_WITH_AUDIO_SB16_CALLBACKS */
2717
2718#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
2719 RTFileDelete(VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "sb16WriteAudio.pcm");
2720#endif
2721
2722 return VINF_SUCCESS;
2723}
2724
2725const PDMDEVREG g_DeviceSB16 =
2726{
2727 /* u32Version */
2728 PDM_DEVREG_VERSION,
2729 /* szName */
2730 "sb16",
2731 /* szRCMod */
2732 "",
2733 /* szR0Mod */
2734 "",
2735 /* pszDescription */
2736 "Sound Blaster 16 Controller",
2737 /* fFlags */
2738 PDM_DEVREG_FLAGS_DEFAULT_BITS,
2739 /* fClass */
2740 PDM_DEVREG_CLASS_AUDIO,
2741 /* cMaxInstances */
2742 1,
2743 /* cbInstance */
2744 sizeof(SB16STATE),
2745 /* pfnConstruct */
2746 sb16Construct,
2747 /* pfnDestruct */
2748 sb16Destruct,
2749 /* pfnRelocate */
2750 NULL,
2751 /* pfnMemSetup */
2752 NULL,
2753 /* pfnPowerOn */
2754 NULL,
2755 /* pfnReset */
2756 sb16DevReset,
2757 /* pfnSuspend */
2758 NULL,
2759 /* pfnResume */
2760 NULL,
2761 /* pfnAttach */
2762 sb16Attach,
2763 /* pfnDetach */
2764 sb16Detach,
2765 /* pfnQueryInterface */
2766 NULL,
2767 /* pfnInitComplete */
2768 NULL,
2769 /* pfnPowerOff */
2770 sb16PowerOff,
2771 /* pfnSoftReset */
2772 NULL,
2773 /* u32VersionEnd */
2774 PDM_DEVREG_VERSION
2775};
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