VirtualBox

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

Last change on this file since 73205 was 73205, checked in by vboxsync, 6 years ago

Audio/SB16: Removed a lot of Doppelmoppel code and added sb16CheckAndReOpenOut() instead.

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