VirtualBox

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

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

Audio: Changed cBits -> cBytes of PDMAUDIOPCMPROPS to avoid some unnecessary calculations (light optimization).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 81.2 KB
Line 
1/* $Id: DevSB16.cpp 73529 2018-08-06 16:26:43Z 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.cBytes = 1 /* 8-bit */;
1039 pCfg->Props.fSigned = false;
1040 pCfg->Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pCfg->Props.cBytes, 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 if (!DrvAudioHlpStreamStatusCanWrite(pDrv->pConnector->pfnStreamGetStatus(pDrv->pConnector, pDrv->Out.pStream)))
1558 continue;
1559
1560 uint32_t cbWrittenToStream = 0;
1561 rc2 = pDrv->pConnector->pfnStreamWrite(pDrv->pConnector, pDrv->Out.pStream, tmpbuf, cbRead, &cbWrittenToStream);
1562
1563 LogFlowFunc(("\tLUN#%RU8: rc=%Rrc, cbWrittenToStream=%RU32\n", pDrv->uLUN, rc2, cbWrittenToStream));
1564 }
1565
1566 cbWritten = cbRead; /* Always report everything written, as the backends need to keep up themselves. */
1567
1568 LogFlowFunc(("\tcbToRead=%RU32, cbToWrite=%RU32, cbWritten=%RU32, cbLeft=%RU32\n",
1569 cbToRead, cbToWrite, cbWritten, cbToWrite - cbWrittenTotal));
1570
1571 Assert(cbToWrite >= cbWritten);
1572 cbToWrite -= cbWritten;
1573 dma_pos = (dma_pos + cbWritten) % dma_len;
1574 cbWrittenTotal += cbWritten;
1575
1576 if (!cbWritten)
1577 break;
1578 }
1579
1580 return cbWrittenTotal;
1581}
1582
1583/**
1584 * @callback_method_impl{FNDMATRANSFERHANDLER,
1585 * Worker callback for both DMA channels.}
1586 */
1587static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
1588{
1589 RT_NOREF(pDevIns);
1590 PSB16STATE pThis = (PSB16STATE)opaque;
1591 int till, copy, written, free;
1592
1593 if (pThis->block_size <= 0)
1594 {
1595 LogFlowFunc(("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
1596 pThis->block_size, nchan, dma_pos, dma_len));
1597 return dma_pos;
1598 }
1599
1600 if (pThis->left_till_irq < 0)
1601 pThis->left_till_irq = pThis->block_size;
1602
1603 free = dma_len;
1604
1605 copy = free;
1606 till = pThis->left_till_irq;
1607
1608#ifdef DEBUG_SB16_MOST
1609 LogFlowFunc(("pos:%06d %d till:%d len:%d\n", dma_pos, free, till, dma_len));
1610#endif
1611
1612 if (copy >= till)
1613 {
1614 if (0 == pThis->dma_auto)
1615 {
1616 copy = till;
1617 }
1618 else
1619 {
1620 if (copy >= till + pThis->block_size)
1621 copy = till; /* Make sure we won't skip IRQs. */
1622 }
1623 }
1624
1625 written = sb16WriteAudio(pThis, nchan, dma_pos, dma_len, copy);
1626 dma_pos = (dma_pos + written) % dma_len;
1627 pThis->left_till_irq -= written;
1628
1629 if (pThis->left_till_irq <= 0)
1630 {
1631 pThis->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
1632 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
1633 if (0 == pThis->dma_auto)
1634 {
1635 sb16Control(pThis, 0);
1636 sb16SpeakerControl(pThis, 0);
1637 }
1638 }
1639
1640 Log3Func(("pos %d/%d free %5d till %5d copy %5d written %5d block_size %5d\n",
1641 dma_pos, dma_len, free, pThis->left_till_irq, copy, written,
1642 pThis->block_size));
1643
1644 while (pThis->left_till_irq <= 0)
1645 pThis->left_till_irq += pThis->block_size;
1646
1647 return dma_pos;
1648}
1649
1650#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
1651
1652static void sb16TimerMaybeStart(PSB16STATE pThis)
1653{
1654 LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
1655
1656 if (pThis->cStreamsActive == 0) /* Only start the timer if there are no active streams. */
1657 return;
1658
1659 if (!pThis->pTimerIO)
1660 return;
1661
1662 /* Set timer flag. */
1663 ASMAtomicXchgBool(&pThis->fTimerActive, true);
1664
1665 /* Update current time timestamp. */
1666 pThis->uTimerTSIO = TMTimerGet(pThis->pTimerIO);
1667
1668 /* Fire off timer. */
1669 TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->cTimerTicksIO);
1670}
1671
1672static void sb16TimerMaybeStop(PSB16STATE pThis)
1673{
1674 LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
1675
1676 if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
1677 return;
1678
1679 if (!pThis->pTimerIO)
1680 return;
1681
1682 /* Set timer flag. */
1683 ASMAtomicXchgBool(&pThis->fTimerActive, false);
1684}
1685
1686/**
1687 * @callback_method_impl{FNTMTIMERDEV}
1688 */
1689static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1690{
1691 RT_NOREF(pDevIns);
1692 PSB16STATE pThis = (PSB16STATE)pvUser;
1693 Assert(pThis == PDMINS_2_DATA(pDevIns, PSB16STATE));
1694 AssertPtr(pThis);
1695
1696 uint64_t cTicksNow = TMTimerGet(pTimer);
1697 bool fIsPlaying = false; /* Whether one or more streams are still playing. */
1698 bool fDoTransfer = false;
1699
1700 pThis->uTimerTSIO = cTicksNow;
1701
1702 PSB16DRIVER pDrv;
1703 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1704 {
1705 PPDMAUDIOSTREAM pStream = pDrv->Out.pStream;
1706 if (!pStream)
1707 continue;
1708
1709 PPDMIAUDIOCONNECTOR pConn = pDrv->pConnector;
1710 if (!pConn)
1711 continue;
1712
1713 int rc2 = pConn->pfnStreamIterate(pConn, pStream);
1714 if (RT_SUCCESS(rc2))
1715 {
1716 rc2 = pConn->pfnStreamPlay(pConn, pStream, NULL /* cPlayed */);
1717 if (RT_FAILURE(rc2))
1718 {
1719 LogFlowFunc(("%s: Failed playing stream, rc=%Rrc\n", pStream->szName, rc2));
1720 continue;
1721 }
1722
1723 /* Only do the next DMA transfer if we're able to write the remaining data block. */
1724 fDoTransfer = pConn->pfnStreamGetWritable(pConn, pStream) > (unsigned)pThis->left_till_irq;
1725 }
1726
1727 PDMAUDIOSTREAMSTS strmSts = pConn->pfnStreamGetStatus(pConn, pStream);
1728 fIsPlaying |= ( (strmSts & PDMAUDIOSTREAMSTS_FLAG_ENABLED)
1729 || (strmSts & PDMAUDIOSTREAMSTS_FLAG_PENDING_DISABLE));
1730 }
1731
1732 bool fTimerActive = ASMAtomicReadBool(&pThis->fTimerActive);
1733 bool fKickTimer = fTimerActive || fIsPlaying;
1734
1735 LogFlowFunc(("fTimerActive=%RTbool, fIsPlaying=%RTbool\n", fTimerActive, fIsPlaying));
1736
1737 if (fDoTransfer)
1738 {
1739 /* Schedule the next transfer. */
1740 PDMDevHlpDMASchedule(pThis->pDevInsR3);
1741
1742 /* Kick the timer at least one more time. */
1743 fKickTimer = true;
1744 }
1745
1746 /*
1747 * Recording.
1748 */
1749 /** @todo Implement recording. */
1750
1751 if (fKickTimer)
1752 {
1753 /* Kick the timer again. */
1754 uint64_t cTicks = pThis->cTimerTicksIO;
1755 /** @todo adjust cTicks down by now much cbOutMin represents. */
1756 TMTimerSet(pThis->pTimerIO, cTicksNow + cTicks);
1757 }
1758}
1759
1760#endif /* !VBOX_WITH_AUDIO_SB16_CALLBACKS */
1761
1762
1763/**
1764 * @callback_method_impl{FNSSMDEVLIVEEXEC}
1765 */
1766static DECLCALLBACK(int) sb16LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1767{
1768 RT_NOREF(uPass);
1769 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1770
1771 SSMR3PutS32(pSSM, pThis->irqCfg);
1772 SSMR3PutS32(pSSM, pThis->dmaCfg);
1773 SSMR3PutS32(pSSM, pThis->hdmaCfg);
1774 SSMR3PutS32(pSSM, pThis->portCfg);
1775 SSMR3PutS32(pSSM, pThis->verCfg);
1776 return VINF_SSM_DONT_CALL_AGAIN;
1777}
1778
1779/**
1780 * Worker for sb16SaveExec.
1781 */
1782static int sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis)
1783{
1784 SSMR3PutS32(pSSM, pThis->irq);
1785 SSMR3PutS32(pSSM, pThis->dma);
1786 SSMR3PutS32(pSSM, pThis->hdma);
1787 SSMR3PutS32(pSSM, pThis->port);
1788 SSMR3PutS32(pSSM, pThis->ver);
1789 SSMR3PutS32(pSSM, pThis->in_index);
1790 SSMR3PutS32(pSSM, pThis->out_data_len);
1791 SSMR3PutS32(pSSM, pThis->fmt_stereo);
1792 SSMR3PutS32(pSSM, pThis->fmt_signed);
1793 SSMR3PutS32(pSSM, pThis->fmt_bits);
1794
1795 SSMR3PutU32(pSSM, pThis->fmt);
1796
1797 SSMR3PutS32(pSSM, pThis->dma_auto);
1798 SSMR3PutS32(pSSM, pThis->block_size);
1799 SSMR3PutS32(pSSM, pThis->fifo);
1800 SSMR3PutS32(pSSM, pThis->freq);
1801 SSMR3PutS32(pSSM, pThis->time_const);
1802 SSMR3PutS32(pSSM, pThis->speaker);
1803 SSMR3PutS32(pSSM, pThis->needed_bytes);
1804 SSMR3PutS32(pSSM, pThis->cmd);
1805 SSMR3PutS32(pSSM, pThis->use_hdma);
1806 SSMR3PutS32(pSSM, pThis->highspeed);
1807 SSMR3PutS32(pSSM, pThis->can_write);
1808 SSMR3PutS32(pSSM, pThis->v2x6);
1809
1810 SSMR3PutU8 (pSSM, pThis->csp_param);
1811 SSMR3PutU8 (pSSM, pThis->csp_value);
1812 SSMR3PutU8 (pSSM, pThis->csp_mode);
1813 SSMR3PutU8 (pSSM, pThis->csp_param); /* Bug compatible! */
1814 SSMR3PutMem(pSSM, pThis->csp_regs, 256);
1815 SSMR3PutU8 (pSSM, pThis->csp_index);
1816 SSMR3PutMem(pSSM, pThis->csp_reg83, 4);
1817 SSMR3PutS32(pSSM, pThis->csp_reg83r);
1818 SSMR3PutS32(pSSM, pThis->csp_reg83w);
1819
1820 SSMR3PutMem(pSSM, pThis->in2_data, sizeof(pThis->in2_data));
1821 SSMR3PutMem(pSSM, pThis->out_data, sizeof(pThis->out_data));
1822 SSMR3PutU8 (pSSM, pThis->test_reg);
1823 SSMR3PutU8 (pSSM, pThis->last_read_byte);
1824
1825 SSMR3PutS32(pSSM, pThis->nzero);
1826 SSMR3PutS32(pSSM, pThis->left_till_irq);
1827 SSMR3PutS32(pSSM, pThis->dma_running);
1828 SSMR3PutS32(pSSM, pThis->bytes_per_second);
1829 SSMR3PutS32(pSSM, pThis->align);
1830
1831 SSMR3PutS32(pSSM, pThis->mixer_nreg);
1832 return SSMR3PutMem(pSSM, pThis->mixer_regs, 256);
1833}
1834
1835/**
1836 * @callback_method_impl{FNSSMDEVSAVEEXEC}
1837 */
1838static DECLCALLBACK(int) sb16SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1839{
1840 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1841
1842 sb16LiveExec(pDevIns, pSSM, 0);
1843 return sb16Save(pSSM, pThis);
1844}
1845
1846/**
1847 * Worker for sb16LoadExec.
1848 */
1849static int sb16Load(PSSMHANDLE pSSM, PSB16STATE pThis)
1850{
1851 SSMR3GetS32(pSSM, &pThis->irq);
1852 SSMR3GetS32(pSSM, &pThis->dma);
1853 SSMR3GetS32(pSSM, &pThis->hdma);
1854 SSMR3GetS32(pSSM, &pThis->port);
1855 SSMR3GetS32(pSSM, &pThis->ver);
1856 SSMR3GetS32(pSSM, &pThis->in_index);
1857 SSMR3GetS32(pSSM, &pThis->out_data_len);
1858 SSMR3GetS32(pSSM, &pThis->fmt_stereo);
1859 SSMR3GetS32(pSSM, &pThis->fmt_signed);
1860 SSMR3GetS32(pSSM, &pThis->fmt_bits);
1861
1862 SSMR3GetU32(pSSM, (uint32_t *)&pThis->fmt);
1863
1864 SSMR3GetS32(pSSM, &pThis->dma_auto);
1865 SSMR3GetS32(pSSM, &pThis->block_size);
1866 SSMR3GetS32(pSSM, &pThis->fifo);
1867 SSMR3GetS32(pSSM, &pThis->freq);
1868 SSMR3GetS32(pSSM, &pThis->time_const);
1869 SSMR3GetS32(pSSM, &pThis->speaker);
1870 SSMR3GetS32(pSSM, &pThis->needed_bytes);
1871 SSMR3GetS32(pSSM, &pThis->cmd);
1872 SSMR3GetS32(pSSM, &pThis->use_hdma);
1873 SSMR3GetS32(pSSM, &pThis->highspeed);
1874 SSMR3GetS32(pSSM, &pThis->can_write);
1875 SSMR3GetS32(pSSM, &pThis->v2x6);
1876
1877 SSMR3GetU8 (pSSM, &pThis->csp_param);
1878 SSMR3GetU8 (pSSM, &pThis->csp_value);
1879 SSMR3GetU8 (pSSM, &pThis->csp_mode);
1880 SSMR3GetU8 (pSSM, &pThis->csp_param); /* Bug compatible! */
1881 SSMR3GetMem(pSSM, pThis->csp_regs, 256);
1882 SSMR3GetU8 (pSSM, &pThis->csp_index);
1883 SSMR3GetMem(pSSM, pThis->csp_reg83, 4);
1884 SSMR3GetS32(pSSM, &pThis->csp_reg83r);
1885 SSMR3GetS32(pSSM, &pThis->csp_reg83w);
1886
1887 SSMR3GetMem(pSSM, pThis->in2_data, sizeof(pThis->in2_data));
1888 SSMR3GetMem(pSSM, pThis->out_data, sizeof(pThis->out_data));
1889 SSMR3GetU8 (pSSM, &pThis->test_reg);
1890 SSMR3GetU8 (pSSM, &pThis->last_read_byte);
1891
1892 SSMR3GetS32(pSSM, &pThis->nzero);
1893 SSMR3GetS32(pSSM, &pThis->left_till_irq);
1894 SSMR3GetS32(pSSM, &pThis->dma_running);
1895 SSMR3GetS32(pSSM, &pThis->bytes_per_second);
1896 SSMR3GetS32(pSSM, &pThis->align);
1897
1898 int32_t mixer_nreg = 0;
1899 int rc = SSMR3GetS32(pSSM, &mixer_nreg);
1900 AssertRCReturn(rc, rc);
1901 pThis->mixer_nreg = (uint8_t)mixer_nreg;
1902 rc = SSMR3GetMem(pSSM, pThis->mixer_regs, 256);
1903 AssertRCReturn(rc, rc);
1904
1905 if (pThis->dma_running)
1906 {
1907 sb16CheckAndReOpenOut(pThis);
1908 sb16Control(pThis, 1);
1909 sb16SpeakerControl(pThis, pThis->speaker);
1910 }
1911
1912 /* Update the master (mixer) and PCM out volumes. */
1913 sb16UpdateVolume(pThis);
1914
1915 return VINF_SUCCESS;
1916}
1917
1918/**
1919 * @callback_method_impl{FNSSMDEVLOADEXEC}
1920 */
1921static DECLCALLBACK(int) sb16LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1922{
1923 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1924
1925 AssertMsgReturn( uVersion == SB16_SAVE_STATE_VERSION
1926 || uVersion == SB16_SAVE_STATE_VERSION_VBOX_30,
1927 ("%u\n", uVersion),
1928 VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
1929 if (uVersion > SB16_SAVE_STATE_VERSION_VBOX_30)
1930 {
1931 int32_t irq;
1932 SSMR3GetS32 (pSSM, &irq);
1933 int32_t dma;
1934 SSMR3GetS32 (pSSM, &dma);
1935 int32_t hdma;
1936 SSMR3GetS32 (pSSM, &hdma);
1937 int32_t port;
1938 SSMR3GetS32 (pSSM, &port);
1939 int32_t ver;
1940 int rc = SSMR3GetS32 (pSSM, &ver);
1941 AssertRCReturn (rc, rc);
1942
1943 if ( irq != pThis->irqCfg
1944 || dma != pThis->dmaCfg
1945 || hdma != pThis->hdmaCfg
1946 || port != pThis->portCfg
1947 || ver != pThis->verCfg)
1948 {
1949 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
1950 N_("config changed: irq=%x/%x dma=%x/%x hdma=%x/%x port=%x/%x ver=%x/%x (saved/config)"),
1951 irq, pThis->irqCfg,
1952 dma, pThis->dmaCfg,
1953 hdma, pThis->hdmaCfg,
1954 port, pThis->portCfg,
1955 ver, pThis->verCfg);
1956 }
1957 }
1958
1959 if (uPass != SSM_PASS_FINAL)
1960 return VINF_SUCCESS;
1961
1962 return sb16Load(pSSM, pThis);
1963}
1964
1965/**
1966 * Creates a PDM audio stream for a specific driver.
1967 *
1968 * @returns IPRT status code.
1969 * @param pThis SB16 state.
1970 * @param pCfg Stream configuration to use.
1971 * @param pDrv Driver stream to create PDM stream for.
1972 */
1973static int sb16CreateDrvStream(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg, PSB16DRIVER pDrv)
1974{
1975 RT_NOREF(pThis);
1976
1977 AssertReturn(pCfg->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER);
1978 Assert(DrvAudioHlpStreamCfgIsValid(pCfg));
1979
1980 PPDMAUDIOSTREAMCFG pCfgHost = DrvAudioHlpStreamCfgDup(pCfg);
1981 if (!pCfgHost)
1982 return VERR_NO_MEMORY;
1983
1984 LogFunc(("[LUN#%RU8] %s\n", pDrv->uLUN, pCfgHost->szName));
1985
1986 AssertMsg(pDrv->Out.pStream == NULL, ("[LUN#%RU8] Driver stream already present when it must not\n", pDrv->uLUN));
1987
1988 int rc = pDrv->pConnector->pfnStreamCreate(pDrv->pConnector, pCfgHost, pCfg /* pCfgGuest */, &pDrv->Out.pStream);
1989 if (RT_SUCCESS(rc))
1990 {
1991 pDrv->pConnector->pfnStreamRetain(pDrv->pConnector, pDrv->Out.pStream);
1992 LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc));
1993 }
1994
1995 RTMemFree(pCfgHost);
1996 return rc;
1997}
1998
1999/**
2000 * Destroys a PDM audio stream of a specific driver.
2001 *
2002 * @param pThis SB16 state.
2003 * @param pDrv Driver stream to destroy PDM stream for.
2004 */
2005static void sb16DestroyDrvStream(PSB16STATE pThis, PSB16DRIVER pDrv)
2006{
2007 AssertPtrReturnVoid(pThis);
2008 AssertPtrReturnVoid(pDrv);
2009
2010 if (pDrv->Out.pStream)
2011 {
2012 pDrv->pConnector->pfnStreamRelease(pDrv->pConnector, pDrv->Out.pStream);
2013
2014 int rc2 = pDrv->pConnector->pfnStreamControl(pDrv->pConnector, pDrv->Out.pStream, PDMAUDIOSTREAMCMD_DISABLE);
2015 AssertRC(rc2);
2016
2017 rc2 = pDrv->pConnector->pfnStreamDestroy(pDrv->pConnector, pDrv->Out.pStream);
2018 AssertRC(rc2);
2019
2020 pDrv->Out.pStream = NULL;
2021 }
2022}
2023
2024/**
2025 * Checks if the output stream needs to be (re-)created and does so if needed.
2026 *
2027 * @return VBox status code.
2028 * @param pThis SB16 state.
2029 */
2030static int sb16CheckAndReOpenOut(PSB16STATE pThis)
2031{
2032 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2033
2034 int rc = VINF_SUCCESS;
2035
2036 if (pThis->freq > 0)
2037 {
2038 /* At the moment we only have one stream, the output stream. */
2039 PDMAUDIOSTREAMCFG Cfg;
2040 RT_ZERO(Cfg);
2041
2042 Cfg.Props.uHz = pThis->freq;
2043 Cfg.Props.cChannels = 1 << pThis->fmt_stereo;
2044 Cfg.Props.cBytes = pThis->fmt_bits / 8;
2045 Cfg.Props.fSigned = RT_BOOL(pThis->fmt_signed);
2046 Cfg.Props.cShift = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(Cfg.Props.cBytes, Cfg.Props.cChannels);
2047
2048 if (!DrvAudioHlpPCMPropsAreEqual(&Cfg.Props, &pThis->Out.Cfg.Props))
2049 {
2050 Cfg.enmDir = PDMAUDIODIR_OUT;
2051 Cfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
2052 Cfg.enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
2053
2054 strcpy(Cfg.szName, "Output");
2055
2056 sb16CloseOut(pThis);
2057
2058 rc = sb16OpenOut(pThis, &Cfg);
2059 AssertRC(rc);
2060 }
2061 }
2062 else
2063 sb16CloseOut(pThis);
2064
2065 LogFlowFuncLeaveRC(rc);
2066 return rc;
2067}
2068
2069static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg)
2070{
2071 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2072 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2073
2074 LogFlowFuncEnter();
2075
2076 if (!DrvAudioHlpStreamCfgIsValid(pCfg))
2077 return VERR_INVALID_PARAMETER;
2078
2079 int rc = DrvAudioHlpStreamCfgCopy(&pThis->Out.Cfg, pCfg);
2080 if (RT_FAILURE(rc))
2081 return rc;
2082
2083 /* Set scheduling hint (if available). */
2084 if (pThis->cTimerTicksIO)
2085 pThis->Out.Cfg.Device.uSchedulingHintMs = 1000 /* ms */ / (TMTimerGetFreq(pThis->pTimerIO) / pThis->cTimerTicksIO);
2086
2087 PSB16DRIVER pDrv;
2088 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2089 {
2090 int rc2 = sb16CreateDrvStream(pThis, &pThis->Out.Cfg, pDrv);
2091 if (RT_FAILURE(rc2))
2092 LogFunc(("Attaching stream failed with %Rrc\n", rc2));
2093
2094 /* Do not pass failure to rc here, as there might be drivers which aren't
2095 * configured / ready yet. */
2096 }
2097
2098 sb16UpdateVolume(pThis);
2099
2100 LogFlowFuncLeaveRC(rc);
2101 return rc;
2102}
2103
2104static void sb16CloseOut(PSB16STATE pThis)
2105{
2106 AssertPtrReturnVoid(pThis);
2107
2108 LogFlowFuncEnter();
2109
2110 PSB16DRIVER pDrv;
2111 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2112 sb16DestroyDrvStream(pThis, pDrv);
2113
2114 LogFlowFuncLeave();
2115}
2116
2117
2118/**
2119 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2120 */
2121static DECLCALLBACK(void *) sb16QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
2122{
2123 PSB16STATE pThis = RT_FROM_MEMBER(pInterface, SB16STATE, IBase);
2124 Assert(&pThis->IBase == pInterface);
2125
2126 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2127 return NULL;
2128}
2129
2130
2131/**
2132 * Attach command, internal version.
2133 *
2134 * This is called to let the device attach to a driver for a specified LUN
2135 * during runtime. This is not called during VM construction, the device
2136 * constructor has to attach to all the available drivers.
2137 *
2138 * @returns VBox status code.
2139 * @param pThis SB16 state.
2140 * @param uLUN The logical unit which is being detached.
2141 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2142 * @param ppDrv Attached driver instance on success. Optional.
2143 */
2144static int sb16AttachInternal(PSB16STATE pThis, unsigned uLUN, uint32_t fFlags, PSB16DRIVER *ppDrv)
2145{
2146 RT_NOREF(fFlags);
2147
2148 /*
2149 * Attach driver.
2150 */
2151 char *pszDesc;
2152 if (RTStrAPrintf(&pszDesc, "Audio driver port (SB16) for LUN #%u", uLUN) <= 0)
2153 AssertLogRelFailedReturn(VERR_NO_MEMORY);
2154
2155 PPDMIBASE pDrvBase;
2156 int rc = PDMDevHlpDriverAttach(pThis->pDevInsR3, uLUN,
2157 &pThis->IBase, &pDrvBase, pszDesc);
2158 if (RT_SUCCESS(rc))
2159 {
2160 PSB16DRIVER pDrv = (PSB16DRIVER)RTMemAllocZ(sizeof(SB16DRIVER));
2161 if (pDrv)
2162 {
2163 pDrv->pDrvBase = pDrvBase;
2164 pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
2165 AssertMsg(pDrv->pConnector != NULL, ("Configuration error: LUN #%u has no host audio interface, rc=%Rrc\n", uLUN, rc));
2166 pDrv->pSB16State = pThis;
2167 pDrv->uLUN = uLUN;
2168
2169 /*
2170 * For now we always set the driver at LUN 0 as our primary
2171 * host backend. This might change in the future.
2172 */
2173 if (pDrv->uLUN == 0)
2174 pDrv->fFlags |= PDMAUDIODRVFLAGS_PRIMARY;
2175
2176 LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->fFlags));
2177
2178 /* Attach to driver list if not attached yet. */
2179 if (!pDrv->fAttached)
2180 {
2181 RTListAppend(&pThis->lstDrv, &pDrv->Node);
2182 pDrv->fAttached = true;
2183 }
2184
2185 if (ppDrv)
2186 *ppDrv = pDrv;
2187 }
2188 else
2189 rc = VERR_NO_MEMORY;
2190 }
2191 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2192 LogFunc(("No attached driver for LUN #%u\n", uLUN));
2193
2194 if (RT_FAILURE(rc))
2195 {
2196 /* Only free this string on failure;
2197 * must remain valid for the live of the driver instance. */
2198 RTStrFree(pszDesc);
2199 }
2200
2201 LogFunc(("iLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
2202 return rc;
2203}
2204
2205/**
2206 * Detach command, internal version.
2207 *
2208 * This is called to let the device detach from a driver for a specified LUN
2209 * during runtime.
2210 *
2211 * @returns VBox status code.
2212 * @param pThis SB16 state.
2213 * @param pDrv Driver to detach device from.
2214 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2215 */
2216static int sb16DetachInternal(PSB16STATE pThis, PSB16DRIVER pDrv, uint32_t fFlags)
2217{
2218 RT_NOREF(fFlags);
2219
2220 sb16DestroyDrvStream(pThis, pDrv);
2221
2222 RTListNodeRemove(&pDrv->Node);
2223
2224 LogFunc(("uLUN=%u, fFlags=0x%x\n", pDrv->uLUN, fFlags));
2225 return VINF_SUCCESS;
2226}
2227
2228/**
2229 * @interface_method_impl{PDMDEVREG,pfnAttach}
2230 */
2231static DECLCALLBACK(int) sb16Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
2232{
2233 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2234
2235 LogFunc(("uLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
2236
2237 PSB16DRIVER pDrv;
2238 int rc2 = sb16AttachInternal(pThis, uLUN, fFlags, &pDrv);
2239 if (RT_SUCCESS(rc2))
2240 rc2 = sb16CreateDrvStream(pThis, &pThis->Out.Cfg, pDrv);
2241
2242 return VINF_SUCCESS;
2243}
2244
2245/**
2246 * @interface_method_impl{PDMDEVREG,pfnDetach}
2247 */
2248static DECLCALLBACK(void) sb16Detach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
2249{
2250 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2251
2252 LogFunc(("uLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
2253
2254 PSB16DRIVER pDrv, pDrvNext;
2255 RTListForEachSafe(&pThis->lstDrv, pDrv, pDrvNext, SB16DRIVER, Node)
2256 {
2257 if (pDrv->uLUN == uLUN)
2258 {
2259 int rc2 = sb16DetachInternal(pThis, pDrv, fFlags);
2260 if (RT_SUCCESS(rc2))
2261 {
2262 RTMemFree(pDrv);
2263 pDrv = NULL;
2264 }
2265
2266 break;
2267 }
2268 }
2269}
2270
2271/**
2272 * Re-attaches (replaces) a driver with a new driver.
2273 *
2274 * @returns VBox status code.
2275 * @param pThis Device instance.
2276 * @param pDrv Driver instance used for attaching to.
2277 * If NULL is specified, a new driver will be created and appended
2278 * to the driver list.
2279 * @param uLUN The logical unit which is being re-detached.
2280 * @param pszDriver New driver name to attach.
2281 */
2282static int sb16Reattach(PSB16STATE pThis, PSB16DRIVER pDrv, uint8_t uLUN, const char *pszDriver)
2283{
2284 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2285 AssertPtrReturn(pszDriver, VERR_INVALID_POINTER);
2286
2287 int rc;
2288
2289 if (pDrv)
2290 {
2291 rc = sb16DetachInternal(pThis, pDrv, 0 /* fFlags */);
2292 if (RT_SUCCESS(rc))
2293 rc = PDMDevHlpDriverDetach(pThis->pDevInsR3, PDMIBASE_2_PDMDRV(pDrv->pDrvBase), 0 /* fFlags */);
2294
2295 if (RT_FAILURE(rc))
2296 return rc;
2297
2298 pDrv = NULL;
2299 }
2300
2301 PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
2302 PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
2303 PCFGMNODE pDev0 = CFGMR3GetChild(pRoot, "Devices/sb16/0/");
2304
2305 /* Remove LUN branch. */
2306 CFGMR3RemoveNode(CFGMR3GetChildF(pDev0, "LUN#%u/", uLUN));
2307
2308 if (pDrv)
2309 {
2310 /* Re-use the driver instance so detach it before. */
2311 rc = PDMDevHlpDriverDetach(pThis->pDevInsR3, PDMIBASE_2_PDMDRV(pDrv->pDrvBase), 0 /* fFlags */);
2312 if (RT_FAILURE(rc))
2313 return rc;
2314 }
2315
2316#define RC_CHECK() if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; }
2317
2318 do
2319 {
2320 PCFGMNODE pLunL0;
2321 rc = CFGMR3InsertNodeF(pDev0, &pLunL0, "LUN#%u/", uLUN); RC_CHECK();
2322 rc = CFGMR3InsertString(pLunL0, "Driver", "AUDIO"); RC_CHECK();
2323 rc = CFGMR3InsertNode(pLunL0, "Config/", NULL); RC_CHECK();
2324
2325 PCFGMNODE pLunL1, pLunL2;
2326 rc = CFGMR3InsertNode (pLunL0, "AttachedDriver/", &pLunL1); RC_CHECK();
2327 rc = CFGMR3InsertNode (pLunL1, "Config/", &pLunL2); RC_CHECK();
2328 rc = CFGMR3InsertString(pLunL1, "Driver", pszDriver); RC_CHECK();
2329
2330 rc = CFGMR3InsertString(pLunL2, "AudioDriver", pszDriver); RC_CHECK();
2331
2332 } while (0);
2333
2334 if (RT_SUCCESS(rc))
2335 rc = sb16AttachInternal(pThis, uLUN, 0 /* fFlags */, NULL /* ppDrv */);
2336
2337 LogFunc(("pThis=%p, uLUN=%u, pszDriver=%s, rc=%Rrc\n", pThis, uLUN, pszDriver, rc));
2338
2339#undef RC_CHECK
2340
2341 return rc;
2342}
2343
2344/**
2345 * @interface_method_impl{PDMDEVREG,pfnReset}
2346 */
2347static DECLCALLBACK(void) sb16DevReset(PPDMDEVINS pDevIns)
2348{
2349 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2350
2351 /* Bring back the device to initial state, and especially make
2352 * sure there's no interrupt or DMA activity.
2353 */
2354 PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
2355
2356 pThis->mixer_regs[0x82] = 0;
2357 pThis->csp_regs[5] = 1;
2358 pThis->csp_regs[9] = 0xf8;
2359
2360 pThis->dma_auto = 0;
2361 pThis->in_index = 0;
2362 pThis->out_data_len = 0;
2363 pThis->left_till_irq = 0;
2364 pThis->needed_bytes = 0;
2365 pThis->block_size = -1;
2366 pThis->nzero = 0;
2367 pThis->highspeed = 0;
2368 pThis->v2x6 = 0;
2369 pThis->cmd = -1;
2370
2371 sb16MixerReset(pThis);
2372 sb16SpeakerControl(pThis, 0);
2373 sb16Control(pThis, 0);
2374 sb16CmdResetLegacy(pThis);
2375}
2376
2377/**
2378 * Powers off the device.
2379 *
2380 * @param pDevIns Device instance to power off.
2381 */
2382static DECLCALLBACK(void) sb16PowerOff(PPDMDEVINS pDevIns)
2383{
2384 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2385
2386 LogRel2(("SB16: Powering off ...\n"));
2387
2388 PSB16DRIVER pDrv;
2389 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2390 sb16DestroyDrvStream(pThis, pDrv);
2391}
2392
2393/**
2394 * @interface_method_impl{PDMDEVREG,pfnDestruct}
2395 */
2396static DECLCALLBACK(int) sb16Destruct(PPDMDEVINS pDevIns)
2397{
2398 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); /* this shall come first */
2399 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2400
2401 LogFlowFuncEnter();
2402
2403 PSB16DRIVER pDrv;
2404 while (!RTListIsEmpty(&pThis->lstDrv))
2405 {
2406 pDrv = RTListGetFirst(&pThis->lstDrv, SB16DRIVER, Node);
2407
2408 RTListNodeRemove(&pDrv->Node);
2409 RTMemFree(pDrv);
2410 }
2411
2412 return VINF_SUCCESS;
2413}
2414
2415static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2416{
2417 RT_NOREF(iInstance);
2418 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* this shall come first */
2419 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2420
2421 /*
2422 * Initialize the data so sb16Destruct runs without a hitch if we return early.
2423 */
2424 pThis->pDevInsR3 = pDevIns;
2425 pThis->IBase.pfnQueryInterface = sb16QueryInterface;
2426 pThis->cmd = -1;
2427
2428 pThis->csp_regs[5] = 1;
2429 pThis->csp_regs[9] = 0xf8;
2430
2431 RTListInit(&pThis->lstDrv);
2432
2433 /*
2434 * Validations.
2435 */
2436 Assert(iInstance == 0);
2437 if (!CFGMR3AreValuesValid(pCfg,
2438 "IRQ\0"
2439 "DMA\0"
2440 "DMA16\0"
2441 "Port\0"
2442 "Version\0"
2443 "TimerHz\0"))
2444 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2445 N_("Invalid configuration for SB16 device"));
2446
2447 /*
2448 * Read config data.
2449 */
2450 int rc = CFGMR3QuerySIntDef(pCfg, "IRQ", &pThis->irq, 5);
2451 if (RT_FAILURE(rc))
2452 return PDMDEV_SET_ERROR(pDevIns, rc,
2453 N_("SB16 configuration error: Failed to get the \"IRQ\" value"));
2454 pThis->irqCfg = pThis->irq;
2455
2456 rc = CFGMR3QuerySIntDef(pCfg, "DMA", &pThis->dma, 1);
2457 if (RT_FAILURE(rc))
2458 return PDMDEV_SET_ERROR(pDevIns, rc,
2459 N_("SB16 configuration error: Failed to get the \"DMA\" value"));
2460 pThis->dmaCfg = pThis->dma;
2461
2462 rc = CFGMR3QuerySIntDef(pCfg, "DMA16", &pThis->hdma, 5);
2463 if (RT_FAILURE(rc))
2464 return PDMDEV_SET_ERROR(pDevIns, rc,
2465 N_("SB16 configuration error: Failed to get the \"DMA16\" value"));
2466 pThis->hdmaCfg = pThis->hdma;
2467
2468 RTIOPORT Port;
2469 rc = CFGMR3QueryPortDef(pCfg, "Port", &Port, 0x220);
2470 if (RT_FAILURE(rc))
2471 return PDMDEV_SET_ERROR(pDevIns, rc,
2472 N_("SB16 configuration error: Failed to get the \"Port\" value"));
2473 pThis->port = Port;
2474 pThis->portCfg = Port;
2475
2476 uint16_t u16Version;
2477 rc = CFGMR3QueryU16Def(pCfg, "Version", &u16Version, 0x0405);
2478 if (RT_FAILURE(rc))
2479 return PDMDEV_SET_ERROR(pDevIns, rc,
2480 N_("SB16 configuration error: Failed to get the \"Version\" value"));
2481 pThis->ver = u16Version;
2482 pThis->verCfg = u16Version;
2483
2484#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
2485 uint16_t uTimerHz;
2486 rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 100 /* Hz */);
2487 if (RT_FAILURE(rc))
2488 return PDMDEV_SET_ERROR(pDevIns, rc,
2489 N_("SB16 configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
2490#endif
2491
2492 /*
2493 * Setup the mixer now that we've got the irq and dma channel numbers.
2494 */
2495 pThis->mixer_regs[0x80] = magic_of_irq(pThis->irq);
2496 pThis->mixer_regs[0x81] = (1 << pThis->dma) | (1 << pThis->hdma);
2497 pThis->mixer_regs[0x82] = 2 << 5;
2498
2499 sb16MixerReset(pThis);
2500
2501 /*
2502 * Create timer(s), register & attach stuff.
2503 */
2504 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIRQ, pThis,
2505 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IRQ timer", &pThis->pTimerIRQ);
2506 if (RT_FAILURE(rc))
2507 AssertMsgFailedReturn(("Error creating IRQ timer, rc=%Rrc\n", rc), rc);
2508
2509 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x04, 2, pThis, mixer_write, mixer_read, NULL, NULL, "SB16");
2510 if (RT_FAILURE(rc))
2511 return rc;
2512 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x06, 10, pThis, dsp_write, dsp_read, NULL, NULL, "SB16");
2513 if (RT_FAILURE(rc))
2514 return rc;
2515
2516 rc = PDMDevHlpDMARegister(pDevIns, pThis->hdma, sb16DMARead, pThis);
2517 if (RT_FAILURE(rc))
2518 return rc;
2519 rc = PDMDevHlpDMARegister(pDevIns, pThis->dma, sb16DMARead, pThis);
2520 if (RT_FAILURE(rc))
2521 return rc;
2522
2523 pThis->can_write = 1;
2524
2525 rc = PDMDevHlpSSMRegister3(pDevIns, SB16_SAVE_STATE_VERSION, sizeof(SB16STATE), sb16LiveExec, sb16SaveExec, sb16LoadExec);
2526 if (RT_FAILURE(rc))
2527 return rc;
2528
2529 /*
2530 * Attach driver.
2531 */
2532 uint8_t uLUN;
2533 for (uLUN = 0; uLUN < UINT8_MAX; ++uLUN)
2534 {
2535 LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
2536 rc = sb16AttachInternal(pThis, uLUN, 0 /* fFlags */, NULL /* ppDrv */);
2537 if (RT_FAILURE(rc))
2538 {
2539 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2540 rc = VINF_SUCCESS;
2541 else if (rc == VERR_AUDIO_BACKEND_INIT_FAILED)
2542 {
2543 sb16Reattach(pThis, NULL /* pDrv */, uLUN, "NullAudio");
2544 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2545 N_("Host audio backend initialization has failed. Selecting the NULL audio backend "
2546 "with the consequence that no sound is audible"));
2547 /* Attaching to the NULL audio backend will never fail. */
2548 rc = VINF_SUCCESS;
2549 }
2550 break;
2551 }
2552 }
2553
2554 LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
2555
2556 sb16CmdResetLegacy(pThis);
2557
2558#ifdef VBOX_WITH_AUDIO_SB16_ONETIME_INIT
2559 PSB16DRIVER pDrv;
2560 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2561 {
2562 /*
2563 * Only primary drivers are critical for the VM to run. Everything else
2564 * might not worth showing an own error message box in the GUI.
2565 */
2566 if (!(pDrv->fFlags & PDMAUDIODRVFLAGS_PRIMARY))
2567 continue;
2568
2569 PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
2570 AssertPtr(pCon);
2571
2572 /** @todo No input streams available for SB16 yet. */
2573
2574 if (!pDrv->Out.pStream)
2575 continue;
2576
2577 bool fValidOut = pCon->pfnStreamGetStatus(pCon, pDrv->Out.pStream) & PDMAUDIOSTREAMSTS_FLAG_INITIALIZED;
2578 if (!fValidOut)
2579 {
2580 LogRel(("SB16: Falling back to NULL backend (no sound audible)\n"));
2581
2582 sb16CmdResetLegacy(pThis);
2583 sb16Reattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
2584
2585 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2586 N_("No audio devices could be opened. Selecting the NULL audio backend "
2587 "with the consequence that no sound is audible"));
2588 }
2589 }
2590#endif
2591
2592#ifndef VBOX_WITH_AUDIO_SB16_CALLBACKS
2593 if (RT_SUCCESS(rc))
2594 {
2595 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIO, pThis,
2596 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IO timer", &pThis->pTimerIO);
2597 if (RT_SUCCESS(rc))
2598 {
2599 pThis->cTimerTicksIO = TMTimerGetFreq(pThis->pTimerIO) / uTimerHz;
2600 pThis->uTimerTSIO = TMTimerGet(pThis->pTimerIO);
2601 LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicksIO, uTimerHz));
2602 }
2603 else
2604 AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
2605 }
2606#else /* !VBOX_WITH_AUDIO_SB16_CALLBACKS */
2607 if (RT_SUCCESS(rc))
2608 {
2609 /** @todo Merge this callback registration with the validation block above once
2610 * this becomes the standard. */
2611 PSB16DRIVER pDrv;
2612 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2613 {
2614 /* Only register primary driver.
2615 * The device emulation does the output multiplexing then. */
2616 if (pDrv->fFlags != PDMAUDIODRVFLAGS_PRIMARY)
2617 continue;
2618
2619 PDMAUDIOCBRECORD AudioCallbacks[2];
2620
2621 SB16CALLBACKCTX Ctx = { pThis, pDrv };
2622
2623 AudioCallbacks[0].enmType = PDMAUDIOCALLBACKTYPE_INPUT;
2624 AudioCallbacks[0].pfnCallback = sb16CallbackInput;
2625 AudioCallbacks[0].pvCtx = &Ctx;
2626 AudioCallbacks[0].cbCtx = sizeof(SB16CALLBACKCTX);
2627
2628 AudioCallbacks[1].enmType = PDMAUDIOCALLBACKTYPE_OUTPUT;
2629 AudioCallbacks[1].pfnCallback = sb16CallbackOutput;
2630 AudioCallbacks[1].pvCtx = &Ctx;
2631 AudioCallbacks[1].cbCtx = sizeof(SB16CALLBACKCTX);
2632
2633 rc = pDrv->pConnector->pfnRegisterCallbacks(pDrv->pConnector, AudioCallbacks, RT_ELEMENTS(AudioCallbacks));
2634 if (RT_FAILURE(rc))
2635 break;
2636 }
2637 }
2638#endif /* VBOX_WITH_AUDIO_SB16_CALLBACKS */
2639
2640#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
2641 RTFileDelete(VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "sb16WriteAudio.pcm");
2642#endif
2643
2644 return VINF_SUCCESS;
2645}
2646
2647const PDMDEVREG g_DeviceSB16 =
2648{
2649 /* u32Version */
2650 PDM_DEVREG_VERSION,
2651 /* szName */
2652 "sb16",
2653 /* szRCMod */
2654 "",
2655 /* szR0Mod */
2656 "",
2657 /* pszDescription */
2658 "Sound Blaster 16 Controller",
2659 /* fFlags */
2660 PDM_DEVREG_FLAGS_DEFAULT_BITS,
2661 /* fClass */
2662 PDM_DEVREG_CLASS_AUDIO,
2663 /* cMaxInstances */
2664 1,
2665 /* cbInstance */
2666 sizeof(SB16STATE),
2667 /* pfnConstruct */
2668 sb16Construct,
2669 /* pfnDestruct */
2670 sb16Destruct,
2671 /* pfnRelocate */
2672 NULL,
2673 /* pfnMemSetup */
2674 NULL,
2675 /* pfnPowerOn */
2676 NULL,
2677 /* pfnReset */
2678 sb16DevReset,
2679 /* pfnSuspend */
2680 NULL,
2681 /* pfnResume */
2682 NULL,
2683 /* pfnAttach */
2684 sb16Attach,
2685 /* pfnDetach */
2686 sb16Detach,
2687 /* pfnQueryInterface */
2688 NULL,
2689 /* pfnInitComplete */
2690 NULL,
2691 /* pfnPowerOff */
2692 sb16PowerOff,
2693 /* pfnSoftReset */
2694 NULL,
2695 /* u32VersionEnd */
2696 PDM_DEVREG_VERSION
2697};
2698
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