VirtualBox

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

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

Audio/SB16: Implemented support for attaching + detaching drivers on runtime.

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