VirtualBox

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

Last change on this file since 82228 was 82228, checked in by vboxsync, 5 years ago

DevHDA,DevIchAc97,DevSB16: Don't stop attaching LUNs/drivers on VERR_AUDIO_BACKEND_INIT_FAILED, only on VERR_PDM_NO_ATTACHED_DRIVER or after 255 LUNs. Use new device helper for reconfguring a LUN to use the 'NullAudio' driver. bugref:9218

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