VirtualBox

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

Last change on this file since 55005 was 55005, checked in by vboxsync, 10 years ago

PDM/Audio: Added volume through virtual mixer.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 60.8 KB
Line 
1/* $Id: DevSB16.cpp 55005 2015-03-30 12:07:39Z vboxsync $ */
2/** @file
3 * DevSB16 - VBox SB16 Audio Controller.
4 *
5 * (r3917 sb16.c)
6 *
7 * @todo hiccups on NT4 and Win98.
8 */
9
10/*
11 * QEMU Soundblaster 16 emulation
12 *
13 * Copyright (c) 2003-2005 Vassili Karpov (malc)
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a copy
16 * of this software and associated documentation files (the "Software"), to deal
17 * in the Software without restriction, including without limitation the rights
18 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19 * copies of the Software, and to permit persons to whom the Software is
20 * furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice shall be included in
23 * all copies or substantial portions of the Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 * THE SOFTWARE.
32 */
33
34#define LOG_GROUP LOG_GROUP_DEV_AUDIO
35#include <VBox/vmm/pdmdev.h>
36#include <VBox/vmm/pdmaudioifs.h>
37#include <iprt/assert.h>
38#include <iprt/string.h>
39#include <iprt/uuid.h>
40#include "vl_vbox.h"
41
42#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
43# include "AudioMixer.h"
44#else
45 extern "C" {
46 #include "audio.h"
47 }
48#endif
49
50#ifndef VBOX
51#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
52#else /* VBOX */
53/** Current saved state version. */
54#define SB16_SAVE_STATE_VERSION 2
55/** The version used in VirtualBox version 3.0 and earlier. This didn't include
56 * the config dump. */
57#define SB16_SAVE_STATE_VERSION_VBOX_30 1
58#endif /* VBOX */
59
60#ifndef VBOX
61#define IO_READ_PROTO(name) \
62 uint32_t name (void *opaque, uint32_t nport)
63#define IO_WRITE_PROTO(name) \
64 void name (void *opaque, uint32_t nport, uint32_t val)
65#else /* VBOX */
66#define IO_READ_PROTO(name) \
67 DECLCALLBACK(int) name (PPDMDEVINS pDevIns, void *opaque, \
68 RTIOPORT nport, uint32_t *pu32, unsigned cb)
69
70#define IO_WRITE_PROTO(name) \
71 DECLCALLBACK(int) name (PPDMDEVINS pDevIns, void *opaque, \
72 RTIOPORT nport, uint32_t val, unsigned cb)
73#endif /* VBOX */
74
75static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
76
77#ifndef VBOX
78static struct {
79 int ver_lo;
80 int ver_hi;
81 int irq;
82 int dma;
83 int hdma;
84 int port;
85} conf = {5, 4, 5, 1, 5, 0x220};
86#endif /* !VBOX */
87
88#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
89typedef struct SB16OUTPUTSTREAM
90{
91 /** PCM output stream. */
92 R3PTRTYPE(PPDMAUDIOGSTSTRMOUT) pStrmOut;
93 /** Mixer handle for output stream. */
94 R3PTRTYPE(PAUDMIXSTREAM) phStrmOut;
95} SB16OUTPUTSTREAM, *PSB16OUTPUTSTREAM;
96
97/**
98 * Struct for maintaining a host backend driver.
99 */
100typedef struct SB16STATE *PSB16STATE;
101typedef struct SB16DRIVER
102{
103 union
104 {
105 /** Node for storing this driver in our device driver
106 * list of AC97STATE. */
107 RTLISTNODE Node;
108 struct
109 {
110 R3PTRTYPE(void *) dummy1;
111 R3PTRTYPE(void *) dummy2;
112 } dummy;
113 };
114
115 /** Pointer to SB16 controller (state). */
116 R3PTRTYPE(PSB16STATE) pSB16State;
117 /** Driver flags. */
118 PDMAUDIODRVFLAGS Flags;
119 uint32_t PaddingFlags;
120 /** LUN # to which this driver has been assigned. */
121 uint8_t uLUN;
122 uint8_t Padding[5];
123 /** Audio connector interface to the underlying
124 * host backend. */
125 R3PTRTYPE(PPDMIAUDIOCONNECTOR) pConnector;
126 /** Stream for output. */
127 SB16OUTPUTSTREAM Out;
128} SB16DRIVER, *PSB16DRIVER;
129#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
130
131typedef struct SB16STATE
132{
133#ifdef VBOX
134 /** Pointer to the device instance. */
135 PPDMDEVINSR3 pDevIns;
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#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
156 PDMAUDIOFMT fmt;
157#else
158 audfmt_e fmt;
159 QEMUSoundCard card;
160#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
161 int dma_auto;
162 int block_size;
163 int fifo;
164 int freq;
165 int time_const;
166 int speaker;
167 int needed_bytes;
168 int cmd;
169 int use_hdma;
170 int highspeed;
171 int can_write;
172
173 int v2x6;
174
175 uint8_t csp_param;
176 uint8_t csp_value;
177 uint8_t csp_mode;
178 uint8_t csp_regs[256];
179 uint8_t csp_index;
180 uint8_t csp_reg83[4];
181 int csp_reg83r;
182 int csp_reg83w;
183
184 uint8_t in2_data[10];
185 uint8_t out_data[50];
186 uint8_t test_reg;
187 uint8_t last_read_byte;
188 int nzero;
189
190 int left_till_irq;
191
192 int dma_running;
193 int bytes_per_second;
194 int align;
195 uint32_t audio_free;
196
197#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
198 R3PTRTYPE(PPDMAUDIOGSTSTRMOUT) pGstStrmOut;
199 /** List of associated LUN drivers. */
200 RTLISTANCHOR lstDrv;
201 /** The device' software mixer. */
202 R3PTRTYPE(PAUDIOMIXER) pMixer;
203 /** Audio sink for PCM output. */
204 R3PTRTYPE(PAUDMIXSINK) pSinkOutput;
205#else
206 SWVoiceOut *voice;
207#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
208
209 PTMTIMER pTimer;
210 PPDMIBASE pDrvBase;
211 /** LUN\#0: Base interface. */
212 PDMIBASE IBase;
213
214 /* mixer state */
215 int mixer_nreg;
216 uint8_t mixer_regs[256];
217} SB16STATE, *PSB16STATE;
218
219#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
220static void sb16AudioCallback(void *pvContext, uint32_t cbFree);
221#else
222static void sb16AudioCallback(void *pvContext, int cbFree);
223#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
224
225static int magic_of_irq (int irq)
226{
227 switch (irq) {
228 case 5:
229 return 2;
230 case 7:
231 return 4;
232 case 9:
233 return 1;
234 case 10:
235 return 8;
236 default:
237 LogFlowFunc(("bad irq %d\n", irq));
238 return 2;
239 }
240}
241
242static int irq_of_magic (int magic)
243{
244 switch (magic) {
245 case 1:
246 return 9;
247 case 2:
248 return 5;
249 case 4:
250 return 7;
251 case 8:
252 return 10;
253 default:
254 LogFlowFunc(("bad irq magic %d\n", magic));
255 return -1;
256 }
257}
258
259#if 0
260static void log_dsp (SB16State *dsp)
261{
262 ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
263 dsp->fmt_stereo ? "Stereo" : "Mono",
264 dsp->fmt_signed ? "Signed" : "Unsigned",
265 dsp->fmt_bits,
266 dsp->dma_auto ? "Auto" : "Single",
267 dsp->block_size,
268 dsp->freq,
269 dsp->time_const,
270 dsp->speaker);
271}
272#endif
273
274static void speaker (PSB16STATE pThis, int on)
275{
276 pThis->speaker = on;
277 /* AUD_enable (pThis->voice, on); */
278}
279
280static void control (PSB16STATE pThis, int hold)
281{
282 int dma = pThis->use_hdma ? pThis->hdma : pThis->dma;
283 pThis->dma_running = hold;
284
285 LogFlowFunc(("hold %d high %d dma %d\n", hold, pThis->use_hdma, dma));
286
287#ifndef VBOX
288 if (hold) {
289 DMA_hold_DREQ (dma);
290 AUD_set_active_out (pThis->voice, 1);
291 }
292 else {
293 DMA_release_DREQ (dma);
294 AUD_set_active_out (pThis->voice, 0);
295 }
296#else /* VBOX */
297 if (hold)
298 {
299 PDMDevHlpDMASetDREQ (pThis->pDevIns, dma, 1);
300 PDMDevHlpDMASchedule (pThis->pDevIns);
301#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
302 pThis->pDrv->pfnEnableOut(pThis->pDrv, pThis->pGstStrmOut, true /* fEnable */);
303#else
304 AUD_set_active_out (pThis->voice, 1);
305#endif
306 }
307 else
308 {
309 PDMDevHlpDMASetDREQ (pThis->pDevIns, dma, 0);
310#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
311 pThis->pDrv->pfnEnableOut(pThis->pDrv, pThis->pGstStrmOut, false /* fEnable */);
312#else
313 AUD_set_active_out (pThis->voice, 0);
314#endif
315 }
316#endif /* VBOX */
317}
318
319#ifndef VBOX
320static void aux_timer (void *opaque)
321{
322 PSB16STATE pThis = opaque;
323 pThis->can_write = 1;
324 qemu_irq_raise (pThis->pic[pThis->irq]);
325}
326#else /* VBOX */
327static DECLCALLBACK(void) sb16Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvThis)
328{
329 PSB16STATE pThis = (SB16STATE *)pvThis;
330 pThis->can_write = 1;
331 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
332}
333#endif /* VBOX */
334
335#define DMA8_AUTO 1
336#define DMA8_HIGH 2
337
338static void continue_dma8 (PSB16STATE pThis)
339{
340 if (pThis->freq > 0)
341 {
342 pThis->audio_free = 0;
343
344#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
345 PDMAUDIOSTREAMCFG as;
346 as.uHz = pThis->freq;
347 as.cChannels = 1 << pThis->fmt_stereo;
348 as.enmFormat = pThis->fmt;
349 as.enmEndianness = PDMAUDIOHOSTENDIANESS;
350
351 int rc = pThis->pDrv->pfnOpenOut(pThis->pDrv, "sb16.out", &as, &pThis->pGstStrmOut);
352 AssertRC(rc);
353#else
354 audsettings_t as;
355 as.freq = pThis->freq;
356 as.nchannels = 1 << pThis->fmt_stereo;
357 as.fmt = pThis->fmt;
358 as.endianness = 0;
359 pThis->voice = AUD_open_out (
360 &pThis->card,
361 pThis->voice,
362 "sb16",
363 pThis,
364 sb16AudioCallback,
365 &as
366 );
367#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
368 }
369
370 control(pThis, 1);
371}
372
373static void dma_cmd8 (PSB16STATE pThis, int mask, int dma_len)
374{
375 pThis->fmt = AUD_FMT_U8;
376 pThis->use_hdma = 0;
377 pThis->fmt_bits = 8;
378 pThis->fmt_signed = 0;
379 pThis->fmt_stereo = (pThis->mixer_regs[0x0e] & 2) != 0;
380 if (-1 == pThis->time_const) {
381 if (pThis->freq <= 0)
382 pThis->freq = 11025;
383 }
384 else {
385 int tmp = (256 - pThis->time_const);
386 pThis->freq = (1000000 + (tmp / 2)) / tmp;
387 }
388
389 if (dma_len != -1) {
390 pThis->block_size = dma_len << pThis->fmt_stereo;
391 }
392 else {
393 /* This is apparently the only way to make both Act1/PL
394 and SecondReality/FC work
395
396 r=andy Wow, actually someone who remembers Future Crew :-)
397
398 Act1 sets block size via command 0x48 and it's an odd number
399 SR does the same with even number
400 Both use stereo, and Creatives own documentation states that
401 0x48 sets block size in bytes less one.. go figure */
402 pThis->block_size &= ~pThis->fmt_stereo;
403 }
404
405 pThis->freq >>= pThis->fmt_stereo;
406 pThis->left_till_irq = pThis->block_size;
407 pThis->bytes_per_second = (pThis->freq << pThis->fmt_stereo);
408 /* pThis->highspeed = (mask & DMA8_HIGH) != 0; */
409 pThis->dma_auto = (mask & DMA8_AUTO) != 0;
410 pThis->align = (1 << pThis->fmt_stereo) - 1;
411
412 if (pThis->block_size & pThis->align) {
413 LogFlowFunc(("warning: misaligned block size %d, alignment %d\n",
414 pThis->block_size, pThis->align + 1));
415 }
416
417 LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, "
418 "dma %d, auto %d, fifo %d, high %d\n",
419 pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
420 pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
421
422 continue_dma8 (pThis);
423 speaker (pThis, 1);
424}
425
426static void dma_cmd (PSB16STATE pThis, uint8_t cmd, uint8_t d0, int dma_len)
427{
428 pThis->use_hdma = cmd < 0xc0;
429 pThis->fifo = (cmd >> 1) & 1;
430 pThis->dma_auto = (cmd >> 2) & 1;
431 pThis->fmt_signed = (d0 >> 4) & 1;
432 pThis->fmt_stereo = (d0 >> 5) & 1;
433
434 switch (cmd >> 4) {
435 case 11:
436 pThis->fmt_bits = 16;
437 break;
438
439 case 12:
440 pThis->fmt_bits = 8;
441 break;
442 }
443
444 if (-1 != pThis->time_const) {
445#if 1
446 int tmp = 256 - pThis->time_const;
447 pThis->freq = (1000000 + (tmp / 2)) / tmp;
448#else
449 /* pThis->freq = 1000000 / ((255 - pThis->time_const) << pThis->fmt_stereo); */
450 pThis->freq = 1000000 / ((255 - pThis->time_const));
451#endif
452 pThis->time_const = -1;
453 }
454
455 pThis->block_size = dma_len + 1;
456 pThis->block_size <<= ((pThis->fmt_bits == 16) ? 1 : 0);
457 if (!pThis->dma_auto) {
458 /* It is clear that for DOOM and auto-init this value
459 shouldn't take stereo into account, while Miles Sound Systems
460 setsound.exe with single transfer mode wouldn't work without it
461 wonders of SB16 yet again */
462 pThis->block_size <<= pThis->fmt_stereo;
463 }
464
465 LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, "
466 "dma %d, auto %d, fifo %d, high %d\n",
467 pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
468 pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
469
470 if (16 == pThis->fmt_bits) {
471 if (pThis->fmt_signed) {
472 pThis->fmt = AUD_FMT_S16;
473 }
474 else {
475 pThis->fmt = AUD_FMT_U16;
476 }
477 }
478 else {
479 if (pThis->fmt_signed) {
480 pThis->fmt = AUD_FMT_S8;
481 }
482 else {
483 pThis->fmt = AUD_FMT_U8;
484 }
485 }
486
487 pThis->left_till_irq = pThis->block_size;
488
489 pThis->bytes_per_second = (pThis->freq << pThis->fmt_stereo) << ((pThis->fmt_bits == 16) ? 1 : 0);
490 pThis->highspeed = 0;
491 pThis->align = (1 << (pThis->fmt_stereo + (pThis->fmt_bits == 16))) - 1;
492 if (pThis->block_size & pThis->align) {
493 LogFlowFunc(("warning: misaligned block size %d, alignment %d\n",
494 pThis->block_size, pThis->align + 1));
495 }
496
497 if (pThis->freq)
498 {
499 pThis->audio_free = 0;
500
501#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
502 PDMAUDIOSTREAMCFG as;
503 as.uHz = pThis->freq;
504 as.cChannels = 1 << pThis->fmt_stereo;
505 as.enmFormat = pThis->fmt;
506 as.enmEndianness = PDMAUDIOHOSTENDIANESS;
507
508 int rc = pThis->pDrv->pfnOpenOut(pThis->pDrv, "sb16.out", &as, &pThis->pGstStrmOut);
509 AssertRC(rc);
510#else
511 audsettings_t as;
512 as.freq = pThis->freq;
513 as.nchannels = 1 << pThis->fmt_stereo;
514 as.fmt = pThis->fmt;
515 as.endianness = 0;
516 pThis->voice = AUD_open_out (
517 &pThis->card,
518 pThis->voice,
519 "sb16",
520 pThis,
521 sb16AudioCallback,
522 &as
523 );
524#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
525 }
526
527 control (pThis, 1);
528 speaker (pThis, 1);
529}
530
531static inline void dsp_out_data (PSB16STATE pThis, uint8_t val)
532{
533 LogFlowFunc(("outdata %#x\n", val));
534 if ((size_t) pThis->out_data_len < sizeof (pThis->out_data)) {
535 pThis->out_data[pThis->out_data_len++] = val;
536 }
537}
538
539static inline uint8_t dsp_get_data (PSB16STATE pThis)
540{
541 if (pThis->in_index) {
542 return pThis->in2_data[--pThis->in_index];
543 }
544 else {
545 LogFlowFunc(("buffer underflow\n"));
546 return 0;
547 }
548}
549
550static void command (PSB16STATE pThis, uint8_t cmd)
551{
552 LogFlowFunc(("command %#x\n", cmd));
553
554 if (cmd > 0xaf && cmd < 0xd0) {
555 if (cmd & 8) {
556 LogFlowFunc(("ADC not yet supported (command %#x)\n", cmd));
557 }
558
559 switch (cmd >> 4) {
560 case 11:
561 case 12:
562 break;
563 default:
564 LogFlowFunc(("%#x wrong bits\n", cmd));
565 }
566 pThis->needed_bytes = 3;
567 }
568 else {
569 pThis->needed_bytes = 0;
570
571 switch (cmd) {
572 case 0x03:
573 dsp_out_data (pThis, 0x10); /* pThis->csp_param); */
574 goto warn;
575
576 case 0x04:
577 pThis->needed_bytes = 1;
578 goto warn;
579
580 case 0x05:
581 pThis->needed_bytes = 2;
582 goto warn;
583
584 case 0x08:
585 /* __asm__ ("int3"); */
586 goto warn;
587
588 case 0x0e:
589 pThis->needed_bytes = 2;
590 goto warn;
591
592 case 0x09:
593 dsp_out_data (pThis, 0xf8);
594 goto warn;
595
596 case 0x0f:
597 pThis->needed_bytes = 1;
598 goto warn;
599
600 case 0x10:
601 pThis->needed_bytes = 1;
602 goto warn;
603
604 case 0x14:
605 pThis->needed_bytes = 2;
606 pThis->block_size = 0;
607 break;
608
609 case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */
610 dma_cmd8 (pThis, DMA8_AUTO, -1);
611 break;
612
613 case 0x20: /* Direct ADC, Juice/PL */
614 dsp_out_data (pThis, 0xff);
615 goto warn;
616
617 case 0x35:
618 LogFlowFunc(("0x35 - MIDI command not implemented\n"));
619 break;
620
621 case 0x40:
622 pThis->freq = -1;
623 pThis->time_const = -1;
624 pThis->needed_bytes = 1;
625 break;
626
627 case 0x41:
628 pThis->freq = -1;
629 pThis->time_const = -1;
630 pThis->needed_bytes = 2;
631 break;
632
633 case 0x42:
634 pThis->freq = -1;
635 pThis->time_const = -1;
636 pThis->needed_bytes = 2;
637 goto warn;
638
639 case 0x45:
640 dsp_out_data (pThis, 0xaa);
641 goto warn;
642
643 case 0x47: /* Continue Auto-Initialize DMA 16bit */
644 break;
645
646 case 0x48:
647 pThis->needed_bytes = 2;
648 break;
649
650 case 0x74:
651 pThis->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
652 LogFlowFunc(("0x75 - DMA DAC, 4-bit ADPCM not implemented\n"));
653 break;
654
655 case 0x75: /* DMA DAC, 4-bit ADPCM Reference */
656 pThis->needed_bytes = 2;
657 LogFlowFunc(("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n"));
658 break;
659
660 case 0x76: /* DMA DAC, 2.6-bit ADPCM */
661 pThis->needed_bytes = 2;
662 LogFlowFunc(("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n"));
663 break;
664
665 case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */
666 pThis->needed_bytes = 2;
667 LogFlowFunc(("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n"));
668 break;
669
670 case 0x7d:
671 LogFlowFunc(("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n"));
672 LogFlowFunc(("not implemented\n"));
673 break;
674
675 case 0x7f:
676 LogFlowFunc(("0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"));
677 LogFlowFunc(("not implemented\n"));
678 break;
679
680 case 0x80:
681 pThis->needed_bytes = 2;
682 break;
683
684 case 0x90:
685 case 0x91:
686 dma_cmd8 (pThis, (((cmd & 1) == 0) ? 1 : 0) | DMA8_HIGH, -1);
687 break;
688
689 case 0xd0: /* halt DMA operation. 8bit */
690 control (pThis, 0);
691 break;
692
693 case 0xd1: /* speaker on */
694 speaker (pThis, 1);
695 break;
696
697 case 0xd3: /* speaker off */
698 speaker (pThis, 0);
699 break;
700
701 case 0xd4: /* continue DMA operation. 8bit */
702 /* KQ6 (or maybe Sierras audblst.drv in general) resets
703 the frequency between halt/continue */
704 continue_dma8 (pThis);
705 break;
706
707 case 0xd5: /* halt DMA operation. 16bit */
708 control (pThis, 0);
709 break;
710
711 case 0xd6: /* continue DMA operation. 16bit */
712 control (pThis, 1);
713 break;
714
715 case 0xd9: /* exit auto-init DMA after this block. 16bit */
716 pThis->dma_auto = 0;
717 break;
718
719 case 0xda: /* exit auto-init DMA after this block. 8bit */
720 pThis->dma_auto = 0;
721 break;
722
723 case 0xe0: /* DSP identification */
724 pThis->needed_bytes = 1;
725 break;
726
727 case 0xe1:
728 dsp_out_data (pThis, pThis->ver & 0xff);
729 dsp_out_data (pThis, pThis->ver >> 8);
730 break;
731
732 case 0xe2:
733 pThis->needed_bytes = 1;
734 goto warn;
735
736 case 0xe3:
737 {
738 int i;
739 for (i = sizeof (e3) - 1; i >= 0; --i)
740 dsp_out_data (pThis, e3[i]);
741 }
742 break;
743
744 case 0xe4: /* write test reg */
745 pThis->needed_bytes = 1;
746 break;
747
748 case 0xe7:
749 LogFlowFunc(("Attempt to probe for ESS (0xe7)?\n"));
750 break;
751
752 case 0xe8: /* read test reg */
753 dsp_out_data (pThis, pThis->test_reg);
754 break;
755
756 case 0xf2:
757 case 0xf3:
758 dsp_out_data (pThis, 0xaa);
759 pThis->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
760#ifndef VBOX
761 qemu_irq_raise (pThis->pic[pThis->irq]);
762#else
763 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
764#endif
765 break;
766
767 case 0xf9:
768 pThis->needed_bytes = 1;
769 goto warn;
770
771 case 0xfa:
772 dsp_out_data (pThis, 0);
773 goto warn;
774
775 case 0xfc: /* FIXME */
776 dsp_out_data (pThis, 0);
777 goto warn;
778
779 default:
780 LogFlowFunc(("Unrecognized command %#x\n", cmd));
781 break;
782 }
783 }
784
785 if (!pThis->needed_bytes) {
786 LogFlow(("\n"));
787 }
788
789 exit:
790 if (!pThis->needed_bytes) {
791 pThis->cmd = -1;
792 }
793 else {
794 pThis->cmd = cmd;
795 }
796 return;
797
798 warn:
799 LogFlowFunc(("warning: command %#x,%d is not truly understood yet\n",
800 cmd, pThis->needed_bytes));
801 goto exit;
802
803}
804
805static uint16_t dsp_get_lohi (PSB16STATE pThis)
806{
807 uint8_t hi = dsp_get_data (pThis);
808 uint8_t lo = dsp_get_data (pThis);
809 return (hi << 8) | lo;
810}
811
812static uint16_t dsp_get_hilo (PSB16STATE pThis)
813{
814 uint8_t lo = dsp_get_data (pThis);
815 uint8_t hi = dsp_get_data (pThis);
816 return (hi << 8) | lo;
817}
818
819static void complete (PSB16STATE pThis)
820{
821 int d0, d1, d2;
822 LogFlowFunc(("complete command %#x, in_index %d, needed_bytes %d\n",
823 pThis->cmd, pThis->in_index, pThis->needed_bytes));
824
825 if (pThis->cmd > 0xaf && pThis->cmd < 0xd0) {
826 d2 = dsp_get_data (pThis);
827 d1 = dsp_get_data (pThis);
828 d0 = dsp_get_data (pThis);
829
830 if (pThis->cmd & 8) {
831 LogFlowFunc(("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
832 pThis->cmd, d0, d1, d2));
833 }
834 else {
835 LogFlowFunc(("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
836 pThis->cmd, d0, d1, d2));
837 dma_cmd (pThis, pThis->cmd, d0, d1 + (d2 << 8));
838 }
839 }
840 else {
841 switch (pThis->cmd) {
842 case 0x04:
843 pThis->csp_mode = dsp_get_data (pThis);
844 pThis->csp_reg83r = 0;
845 pThis->csp_reg83w = 0;
846 LogFlowFunc(("CSP command 0x04: mode=%#x\n", pThis->csp_mode));
847 break;
848
849 case 0x05:
850 pThis->csp_param = dsp_get_data (pThis);
851 pThis->csp_value = dsp_get_data (pThis);
852 LogFlowFunc(("CSP command 0x05: param=%#x value=%#x\n",
853 pThis->csp_param,
854 pThis->csp_value));
855 break;
856
857 case 0x0e:
858 d0 = dsp_get_data (pThis);
859 d1 = dsp_get_data (pThis);
860 LogFlowFunc(("write CSP register %d <- %#x\n", d1, d0));
861 if (d1 == 0x83) {
862 LogFlowFunc(("0x83[%d] <- %#x\n", pThis->csp_reg83r, d0));
863 pThis->csp_reg83[pThis->csp_reg83r % 4] = d0;
864 pThis->csp_reg83r += 1;
865 }
866 else {
867 pThis->csp_regs[d1] = d0;
868 }
869 break;
870
871 case 0x0f:
872 d0 = dsp_get_data (pThis);
873 LogFlowFunc(("read CSP register %#x -> %#x, mode=%#x\n",
874 d0, pThis->csp_regs[d0], pThis->csp_mode));
875 if (d0 == 0x83) {
876 LogFlowFunc(("0x83[%d] -> %#x\n",
877 pThis->csp_reg83w,
878 pThis->csp_reg83[pThis->csp_reg83w % 4]));
879 dsp_out_data (pThis, pThis->csp_reg83[pThis->csp_reg83w % 4]);
880 pThis->csp_reg83w += 1;
881 }
882 else {
883 dsp_out_data (pThis, pThis->csp_regs[d0]);
884 }
885 break;
886
887 case 0x10:
888 d0 = dsp_get_data (pThis);
889 LogFlowFunc(("cmd 0x10 d0=%#x\n", d0));
890 break;
891
892 case 0x14:
893 dma_cmd8 (pThis, 0, dsp_get_lohi (pThis) + 1);
894 break;
895
896 case 0x40:
897 pThis->time_const = dsp_get_data (pThis);
898 LogFlowFunc(("set time const %d\n", pThis->time_const));
899 break;
900
901 case 0x42: /* FT2 sets output freq with this, go figure */
902#if 0
903 LogFlowFunc(("cmd 0x42 might not do what it think it should\n"));
904#endif
905 case 0x41:
906 pThis->freq = dsp_get_hilo (pThis);
907 LogFlowFunc(("set freq %d\n", pThis->freq));
908 break;
909
910 case 0x48:
911 pThis->block_size = dsp_get_lohi (pThis) + 1;
912 LogFlowFunc(("set dma block len %d\n", pThis->block_size));
913 break;
914
915 case 0x74:
916 case 0x75:
917 case 0x76:
918 case 0x77:
919 /* ADPCM stuff, ignore */
920 break;
921
922 case 0x80:
923 {
924 int freq, samples, bytes;
925 uint64_t ticks;
926
927 freq = pThis->freq > 0 ? pThis->freq : 11025;
928 samples = dsp_get_lohi (pThis) + 1;
929 bytes = samples << pThis->fmt_stereo << ((pThis->fmt_bits == 16) ? 1 : 0);
930#ifndef VBOX
931 ticks = (bytes * ticks_per_sec) / freq;
932 if (ticks < ticks_per_sec / 1024) {
933 qemu_irq_raise (pThis->pic[pThis->irq]);
934 }
935 else {
936 if (pThis->aux_ts) {
937 qemu_mod_timer (
938 pThis->aux_ts,
939 qemu_get_clock (vm_clock) + ticks
940 );
941 }
942 }
943 LogFlowFunc(("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks));
944#else /* VBOX */
945 ticks = (bytes * TMTimerGetFreq(pThis->pTimer)) / freq;
946 if (ticks < TMTimerGetFreq(pThis->pTimer) / 1024)
947 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
948 else
949 TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + ticks);
950 LogFlowFunc(("mix silence %d %d % %RU64\n", samples, bytes, ticks));
951#endif /* VBOX */
952 }
953 break;
954
955 case 0xe0:
956 d0 = dsp_get_data (pThis);
957 pThis->out_data_len = 0;
958 LogFlowFunc(("E0 data = %#x\n", d0));
959 dsp_out_data (pThis, ~d0);
960 break;
961
962 case 0xe2:
963 d0 = dsp_get_data (pThis);
964 LogFlow(("SB16:E2 = %#x\n", d0));
965 break;
966
967 case 0xe4:
968 pThis->test_reg = dsp_get_data (pThis);
969 break;
970
971 case 0xf9:
972 d0 = dsp_get_data (pThis);
973 LogFlowFunc(("command 0xf9 with %#x\n", d0));
974 switch (d0) {
975 case 0x0e:
976 dsp_out_data (pThis, 0xff);
977 break;
978
979 case 0x0f:
980 dsp_out_data (pThis, 0x07);
981 break;
982
983 case 0x37:
984 dsp_out_data (pThis, 0x38);
985 break;
986
987 default:
988 dsp_out_data (pThis, 0x00);
989 break;
990 }
991 break;
992
993 default:
994 LogFlowFunc(("complete: unrecognized command %#x\n", pThis->cmd));
995 return;
996 }
997 }
998
999 LogFlow(("\n"));
1000 pThis->cmd = -1;
1001 return;
1002}
1003
1004static void legacy_reset (PSB16STATE pThis)
1005{
1006 pThis->freq = 11025;
1007 pThis->fmt_signed = 0;
1008 pThis->fmt_bits = 8;
1009 pThis->fmt_stereo = 0;
1010
1011#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1012 PDMAUDIOSTREAMCFG as;
1013 as.uHz = pThis->freq;
1014 as.cChannels = 1;
1015 as.enmFormat = AUD_FMT_U8;
1016 as.enmEndianness = PDMAUDIOHOSTENDIANESS;
1017
1018 int rc = pThis->pDrv->pfnOpenOut(pThis->pDrv, "sb16.out", &as, &pThis->pGstStrmOut);
1019 AssertRC(rc);
1020#else
1021 audsettings_t as;
1022 as.freq = pThis->freq;
1023 as.nchannels = 1;
1024 as.fmt = AUD_FMT_U8;
1025 as.endianness = 0;
1026 pThis->voice = AUD_open_out (
1027 &pThis->card,
1028 pThis->voice,
1029 "sb16",
1030 pThis,
1031 sb16AudioCallback,
1032 &as
1033 );
1034#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1035
1036 /* Not sure about that... */
1037 /* AUD_set_active_out (pThis->voice, 1); */
1038}
1039
1040static void reset (PSB16STATE pThis)
1041{
1042#ifndef VBOX
1043 qemu_irq_lower (pThis->pic[pThis->irq]);
1044 if (pThis->dma_auto) {
1045 qemu_irq_raise (pThis->pic[pThis->irq]);
1046 qemu_irq_lower (pThis->pic[pThis->irq]);
1047 }
1048#else /* VBOX */
1049 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1050 if (pThis->dma_auto) {
1051 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
1052 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1053 }
1054#endif /* VBOX */
1055
1056 pThis->mixer_regs[0x82] = 0;
1057 pThis->dma_auto = 0;
1058 pThis->in_index = 0;
1059 pThis->out_data_len = 0;
1060 pThis->left_till_irq = 0;
1061 pThis->needed_bytes = 0;
1062 pThis->block_size = -1;
1063 pThis->nzero = 0;
1064 pThis->highspeed = 0;
1065 pThis->v2x6 = 0;
1066 pThis->cmd = -1;
1067
1068 dsp_out_data(pThis, 0xaa);
1069 speaker (pThis, 0);
1070 control (pThis, 0);
1071 legacy_reset (pThis);
1072}
1073
1074static IO_WRITE_PROTO (dsp_write)
1075{
1076 PSB16STATE pThis = (SB16STATE*)opaque;
1077 int iport = nport - pThis->port;
1078
1079 LogFlowFunc(("write %#x <- %#x\n", nport, val));
1080 switch (iport) {
1081 case 0x06:
1082 switch (val) {
1083 case 0x00:
1084 if (pThis->v2x6 == 1) {
1085 if (0 && pThis->highspeed) {
1086 pThis->highspeed = 0;
1087#ifndef VBOX
1088 qemu_irq_lower (pThis->pic[pThis->irq]);
1089#else
1090 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1091#endif
1092 control (pThis, 0);
1093 }
1094 else {
1095 reset (pThis);
1096 }
1097 }
1098 pThis->v2x6 = 0;
1099 break;
1100
1101 case 0x01:
1102 case 0x03: /* FreeBSD kludge */
1103 pThis->v2x6 = 1;
1104 break;
1105
1106 case 0xc6:
1107 pThis->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */
1108 break;
1109
1110 case 0xb8: /* Panic */
1111 reset (pThis);
1112 break;
1113
1114 case 0x39:
1115 dsp_out_data (pThis, 0x38);
1116 reset (pThis);
1117 pThis->v2x6 = 0x39;
1118 break;
1119
1120 default:
1121 pThis->v2x6 = val;
1122 break;
1123 }
1124 break;
1125
1126 case 0x0c: /* write data or command | write status */
1127/* if (pThis->highspeed) */
1128/* break; */
1129
1130 if (0 == pThis->needed_bytes) {
1131 command (pThis, val);
1132#if 0
1133 if (0 == pThis->needed_bytes) {
1134 log_dsp (pThis);
1135 }
1136#endif
1137 }
1138 else {
1139 if (pThis->in_index == sizeof (pThis->in2_data)) {
1140 LogFlowFunc(("in data overrun\n"));
1141 }
1142 else {
1143 pThis->in2_data[pThis->in_index++] = val;
1144 if (pThis->in_index == pThis->needed_bytes) {
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#ifdef VBOX
1161 return VINF_SUCCESS;
1162#endif
1163}
1164
1165static IO_READ_PROTO (dsp_read)
1166{
1167 PSB16STATE pThis = (SB16STATE*)opaque;
1168 int iport, retval, ack = 0;
1169
1170 iport = nport - pThis->port;
1171#ifdef VBOX
1172 /** @todo reject non-byte access?
1173 * The spec does not mention a non-byte access so we should check how real hardware behaves. */
1174#endif
1175
1176 switch (iport) {
1177 case 0x06: /* reset */
1178 retval = 0xff;
1179 break;
1180
1181 case 0x0a: /* read data */
1182 if (pThis->out_data_len) {
1183 retval = pThis->out_data[--pThis->out_data_len];
1184 pThis->last_read_byte = retval;
1185 }
1186 else {
1187 if (pThis->cmd != -1) {
1188 LogFlowFunc(("empty output buffer for command %#x\n",
1189 pThis->cmd));
1190 }
1191 retval = pThis->last_read_byte;
1192 /* goto error; */
1193 }
1194 break;
1195
1196 case 0x0c: /* 0 can write */
1197 retval = pThis->can_write ? 0 : 0x80;
1198 break;
1199
1200 case 0x0d: /* timer interrupt clear */
1201 /* LogFlowFunc(("timer interrupt clear\n")); */
1202 retval = 0;
1203 break;
1204
1205 case 0x0e: /* data available status | irq 8 ack */
1206 retval = (!pThis->out_data_len || pThis->highspeed) ? 0 : 0x80;
1207 if (pThis->mixer_regs[0x82] & 1) {
1208 ack = 1;
1209 pThis->mixer_regs[0x82] &= ~1;
1210#ifndef VBOX
1211 qemu_irq_lower (pThis->pic[pThis->irq]);
1212#else
1213 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1214#endif
1215 }
1216 break;
1217
1218 case 0x0f: /* irq 16 ack */
1219 retval = 0xff;
1220 if (pThis->mixer_regs[0x82] & 2) {
1221 ack = 1;
1222 pThis->mixer_regs[0x82] &= ~2;
1223#ifndef VBOX
1224 qemu_irq_lower (pThis->pic[pThis->irq]);
1225#else
1226 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1227#endif
1228 }
1229 break;
1230
1231 default:
1232 goto error;
1233 }
1234
1235 if (!ack) {
1236 LogFlowFunc(("read %#x -> %#x\n", nport, retval));
1237 }
1238
1239#ifndef VBOX
1240 return retval;
1241#else
1242 *pu32 = retval;
1243 return VINF_SUCCESS;
1244#endif
1245
1246 error:
1247 LogFlowFunc(("warning: dsp_read %#x error\n", nport));
1248#ifndef VBOX
1249 return 0xff;
1250#else
1251 return VERR_IOM_IOPORT_UNUSED;
1252#endif
1253}
1254
1255static void reset_mixer (PSB16STATE pThis)
1256{
1257 int i;
1258
1259 memset (pThis->mixer_regs, 0xff, 0x7f);
1260 memset (pThis->mixer_regs + 0x83, 0xff, sizeof (pThis->mixer_regs) - 0x83);
1261
1262 pThis->mixer_regs[0x02] = 4; /* master volume 3bits */
1263 pThis->mixer_regs[0x06] = 4; /* MIDI volume 3bits */
1264 pThis->mixer_regs[0x08] = 0; /* CD volume 3bits */
1265 pThis->mixer_regs[0x0a] = 0; /* voice volume 2bits */
1266
1267 /* d5=input filt, d3=lowpass filt, d1,d2=input source */
1268 pThis->mixer_regs[0x0c] = 0;
1269
1270 /* d5=output filt, d1=stereo switch */
1271 pThis->mixer_regs[0x0e] = 0;
1272
1273 /* voice volume L d5,d7, R d1,d3 */
1274 pThis->mixer_regs[0x04] = (4 << 5) | (4 << 1);
1275 /* master ... */
1276 pThis->mixer_regs[0x22] = (4 << 5) | (4 << 1);
1277 /* MIDI ... */
1278 pThis->mixer_regs[0x26] = (4 << 5) | (4 << 1);
1279
1280 for (i = 0x30; i < 0x48; i++) {
1281 pThis->mixer_regs[i] = 0x20;
1282 }
1283}
1284
1285static IO_WRITE_PROTO(mixer_write_indexb)
1286{
1287 PSB16STATE pThis = (SB16STATE*)opaque;
1288 (void) nport;
1289 pThis->mixer_nreg = val;
1290
1291#ifdef VBOX
1292 return VINF_SUCCESS;
1293#endif
1294}
1295
1296#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
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&-u)-1); /** @todo r=andy Un/signed mismatch? */
1310}
1311#endif
1312
1313static IO_WRITE_PROTO(mixer_write_datab)
1314{
1315 PSB16STATE pThis = (PSB16STATE)opaque;
1316 bool fUpdateMaster = false;
1317 bool fUpdateStream = false;
1318
1319 (void) nport;
1320 LogFlowFunc(("mixer_write [%#x] <- %#x\n", pThis->mixer_nreg, val));
1321
1322 switch (pThis->mixer_nreg)
1323 {
1324 case 0x00:
1325 reset_mixer(pThis);
1326 /* And update the actual volume, too. */
1327 fUpdateMaster = true;
1328 fUpdateStream = true;
1329 break;
1330
1331 case 0x04:
1332 /* Translate from old style stream volume (L/R). */
1333 pThis->mixer_regs[0x32] = val & 0xff;
1334 pThis->mixer_regs[0x33] = val << 4;
1335 fUpdateStream = true;
1336 break;
1337
1338 case 0x22:
1339 /* Translate from old style master volume (L/R). */
1340 pThis->mixer_regs[0x30] = val & 0xff;
1341 pThis->mixer_regs[0x31] = val << 4;
1342 fUpdateMaster = true;
1343 break;
1344
1345 case 0x30:
1346 /* Translate to old style master volume (L). */
1347 pThis->mixer_regs[0x22] = (pThis->mixer_regs[0x22] & 0x0f) | val;
1348 fUpdateMaster = true;
1349 break;
1350
1351 case 0x31:
1352 /* Translate to old style master volume (R). */
1353 pThis->mixer_regs[0x22] = (pThis->mixer_regs[0x22] & 0xf0) | (val >> 4);
1354 fUpdateMaster = true;
1355 break;
1356
1357 case 0x32:
1358 /* Translate to old style stream volume (L). */
1359 pThis->mixer_regs[0x04] = (pThis->mixer_regs[0x04] & 0x0f) | val;
1360 fUpdateStream = true;
1361 break;
1362
1363 case 0x33:
1364 /* Translate to old style stream volume (R). */
1365 pThis->mixer_regs[0x04] = (pThis->mixer_regs[0x04] & 0xf0) | (val >> 4);
1366 fUpdateStream = true;
1367 break;
1368
1369 case 0x80:
1370 {
1371 int irq = irq_of_magic(val);
1372 LogFlowFunc(("setting irq to %d (val=%#x)\n", irq, val));
1373 if (irq > 0)
1374 pThis->irq = irq;
1375 break;
1376 }
1377
1378 case 0x81:
1379 {
1380 int dma, hdma;
1381
1382 dma = lsbindex (val & 0xf);
1383 hdma = lsbindex (val & 0xf0);
1384 if (dma != pThis->dma || hdma != pThis->hdma)
1385 LogFlow(("SB16: attempt to change DMA 8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
1386 dma, pThis->dma, hdma, pThis->hdma, val));
1387#if 0
1388 pThis->dma = dma;
1389 pThis->hdma = hdma;
1390#endif
1391 break;
1392 }
1393
1394 case 0x82:
1395 LogFlowFunc(("attempt to write into IRQ status register (val=%#x)\n", val));
1396#ifdef VBOX
1397 return VINF_SUCCESS;
1398#endif
1399
1400 default:
1401 if (pThis->mixer_nreg >= 0x80)
1402 LogFlowFunc(("attempt to write mixer[%#x] <- %#x\n", pThis->mixer_nreg, val));
1403 break;
1404 }
1405
1406 pThis->mixer_regs[pThis->mixer_nreg] = val;
1407
1408#ifdef VBOX
1409 /* Update the master (mixer) volume. */
1410 if (fUpdateMaster)
1411 {
1412 int mute = 0; /** @todo Handle (un)muting. */
1413 uint8_t lvol = pThis->mixer_regs[0x30];
1414 uint8_t rvol = pThis->mixer_regs[0x31];
1415
1416#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1417 PDMAUDIOVOLUME vol = { RT_BOOL(mute), lvol, rvol };
1418 audioMixerSetMasterVolume(pThis->pMixer, &vol);
1419#else
1420 AUD_set_volume(AUD_MIXER_VOLUME, &mute, &lvol, &rvol);
1421#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1422 }
1423
1424 /* Update the stream (PCM) volume. */
1425 if (fUpdateStream)
1426 {
1427 int mute = 0; /** @todo Handle (un)muting. */
1428 uint8_t lvol = pThis->mixer_regs[0x32];
1429 uint8_t rvol = pThis->mixer_regs[0x33];
1430
1431#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1432 PDMAUDIOVOLUME vol = { RT_BOOL(mute), lvol, rvol };
1433 audioMixerSetSinkVolume(pThis->pSinkOutput, &vol);
1434#else
1435 AUD_set_volume(AUD_MIXER_PCM, &mute, &lvol, &rvol);
1436#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1437 }
1438#endif /* VBOX */
1439
1440#ifdef VBOX
1441 return VINF_SUCCESS;
1442#endif
1443}
1444
1445static IO_WRITE_PROTO(mixer_write)
1446{
1447#ifndef VBOX
1448 mixer_write_indexb (opaque, nport, val & 0xff);
1449 mixer_write_datab (opaque, nport, (val >> 8) & 0xff);
1450#else /* VBOX */
1451 PSB16STATE pThis = (SB16STATE*)opaque;
1452 int iport = nport - pThis->port;
1453 switch (cb)
1454 {
1455 case 1:
1456 switch (iport)
1457 {
1458 case 4:
1459 mixer_write_indexb (pDevIns, opaque, nport, val, 1);
1460 break;
1461 case 5:
1462 mixer_write_datab (pDevIns, opaque, nport, val, 1);
1463 break;
1464 }
1465 break;
1466 case 2:
1467 mixer_write_indexb (pDevIns, opaque, nport, val & 0xff, 1);
1468 mixer_write_datab (pDevIns, opaque, nport, (val >> 8) & 0xff, 1);
1469 break;
1470 default:
1471 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", nport, cb, val));
1472 break;
1473 }
1474 return VINF_SUCCESS;
1475#endif /* VBOX */
1476}
1477
1478static IO_READ_PROTO(mixer_read)
1479{
1480 PSB16STATE pThis = (SB16STATE*)opaque;
1481
1482 (void) nport;
1483#ifndef DEBUG_SB16_MOST
1484 if (pThis->mixer_nreg != 0x82) {
1485 LogFlowFunc(("mixer_read[%#x] -> %#x\n",
1486 pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
1487 }
1488#else
1489 LogFlowFunc(("mixer_read[%#x] -> %#x\n",
1490 pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
1491#endif
1492#ifndef VBOX
1493 return pThis->mixer_regs[pThis->mixer_nreg];
1494#else
1495 *pu32 = pThis->mixer_regs[pThis->mixer_nreg];
1496 return VINF_SUCCESS;
1497#endif
1498}
1499
1500static int write_audio (PSB16STATE pThis, int nchan, int dma_pos,
1501 int dma_len, int len)
1502{
1503 int temp, net;
1504 uint8_t tmpbuf[_4K];
1505
1506 temp = len;
1507 net = 0;
1508
1509 while (temp)
1510 {
1511 int left = dma_len - dma_pos;
1512#ifndef VBOX
1513 size_t to_copy;
1514 int copied;
1515#else
1516 size_t to_copy;
1517 uint32_t copied;
1518#endif
1519
1520 to_copy = RT_MIN(temp, left);
1521 if (to_copy > sizeof(tmpbuf))
1522 to_copy = sizeof(tmpbuf);
1523
1524#ifndef VBOX
1525 copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
1526#else
1527 int rc = PDMDevHlpDMAReadMemory(pThis->pDevIns, nchan, tmpbuf, dma_pos,
1528 to_copy, &copied);
1529 AssertMsgRC (rc, ("DMAReadMemory -> %Rrc\n", rc));
1530#endif
1531
1532#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1533 rc = pThis->pDrv->pfnWrite(pThis->pDrv, pThis->pGstStrmOut, tmpbuf, to_copy, &copied);
1534 if (RT_FAILURE(rc))
1535 break;
1536#else
1537 copied = AUD_write (pThis->voice, tmpbuf, copied);
1538#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1539
1540 temp -= copied;
1541 dma_pos = (dma_pos + copied) % dma_len;
1542 net += copied;
1543
1544 if (!copied)
1545 break;
1546 }
1547
1548 return net;
1549}
1550
1551#ifndef VBOX
1552static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
1553#else
1554static DECLCALLBACK(uint32_t) SB_read_DMA (PPDMDEVINS pDevIns, void *opaque, unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
1555#endif
1556{
1557 PSB16STATE pThis = (SB16STATE*)opaque;
1558 int till, copy, written, free;
1559
1560 if (pThis->block_size <= 0) {
1561 LogFlowFunc(("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
1562 pThis->block_size, nchan, dma_pos, dma_len));
1563 return dma_pos;
1564 }
1565
1566 if (pThis->left_till_irq < 0) {
1567 pThis->left_till_irq = pThis->block_size;
1568 }
1569
1570#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1571 if (pThis->pGstStrmOut) {
1572#else
1573 if (pThis->voice) {
1574#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1575 free = pThis->audio_free & ~pThis->align;
1576 if ((free <= 0) || !dma_len) {
1577 return dma_pos;
1578 }
1579 }
1580 else {
1581 free = dma_len;
1582 }
1583
1584 copy = free;
1585 till = pThis->left_till_irq;
1586
1587#ifdef DEBUG_SB16_MOST
1588 LogFlowFunc(("pos:%06d %d till:%d len:%d\n",
1589 dma_pos, free, till, dma_len));
1590#endif
1591
1592 if (copy >= till) {
1593 if (0 == pThis->dma_auto) {
1594 copy = till;
1595 } else {
1596 if( copy >= till + pThis->block_size ) {
1597 copy = till; /* Make sure we won't skip IRQs. */
1598 }
1599 }
1600 }
1601
1602 written = write_audio (pThis, nchan, dma_pos, dma_len, copy);
1603 dma_pos = (dma_pos + written) % dma_len;
1604 pThis->left_till_irq -= written;
1605
1606 if (pThis->left_till_irq <= 0) {
1607 pThis->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
1608#ifndef VBOX
1609 qemu_irq_raise (pThis->pic[pThis->irq]);
1610#else
1611 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
1612#endif
1613 if (0 == pThis->dma_auto) {
1614 control (pThis, 0);
1615 speaker (pThis, 0);
1616 }
1617 }
1618
1619#ifdef DEBUG_SB16_MOST
1620 LogFlowFunc(("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
1621 dma_pos, free, dma_len, pThis->left_till_irq, copy, written,
1622 pThis->block_size));
1623#endif
1624
1625 while (pThis->left_till_irq <= 0) {
1626 pThis->left_till_irq = pThis->block_size + pThis->left_till_irq;
1627 }
1628
1629 return dma_pos;
1630}
1631
1632#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1633static void sb16AudioCallback(void *pvContext, uint32_t cbFree)
1634#else
1635static void sb16AudioCallback(void *pvContext, int cbFree)
1636#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1637{
1638 SB16STATE *pState = (SB16STATE*)pvContext;
1639 AssertPtrReturnVoid(pState);
1640 pState->audio_free = cbFree;
1641#ifdef VBOX
1642 /* New space available, see if we can transfer more. There is no cyclic DMA timer in VBox. */
1643 PDMDevHlpDMASchedule(pState->pDevIns);
1644#endif
1645}
1646
1647static void SB_save (QEMUFile *f, void *opaque)
1648{
1649#ifndef VBOX
1650 PSB16STATE pThis = opaque;
1651#else
1652 PSB16STATE pThis = (SB16STATE *)opaque;
1653#endif
1654
1655 qemu_put_be32 (f, pThis->irq);
1656 qemu_put_be32 (f, pThis->dma);
1657 qemu_put_be32 (f, pThis->hdma);
1658 qemu_put_be32 (f, pThis->port);
1659 qemu_put_be32 (f, pThis->ver);
1660 qemu_put_be32 (f, pThis->in_index);
1661 qemu_put_be32 (f, pThis->out_data_len);
1662 qemu_put_be32 (f, pThis->fmt_stereo);
1663 qemu_put_be32 (f, pThis->fmt_signed);
1664 qemu_put_be32 (f, pThis->fmt_bits);
1665 qemu_put_be32s (f, &pThis->fmt);
1666 qemu_put_be32 (f, pThis->dma_auto);
1667 qemu_put_be32 (f, pThis->block_size);
1668 qemu_put_be32 (f, pThis->fifo);
1669 qemu_put_be32 (f, pThis->freq);
1670 qemu_put_be32 (f, pThis->time_const);
1671 qemu_put_be32 (f, pThis->speaker);
1672 qemu_put_be32 (f, pThis->needed_bytes);
1673 qemu_put_be32 (f, pThis->cmd);
1674 qemu_put_be32 (f, pThis->use_hdma);
1675 qemu_put_be32 (f, pThis->highspeed);
1676 qemu_put_be32 (f, pThis->can_write);
1677 qemu_put_be32 (f, pThis->v2x6);
1678
1679 qemu_put_8s (f, &pThis->csp_param);
1680 qemu_put_8s (f, &pThis->csp_value);
1681 qemu_put_8s (f, &pThis->csp_mode);
1682 qemu_put_8s (f, &pThis->csp_param);
1683 qemu_put_buffer (f, pThis->csp_regs, 256);
1684 qemu_put_8s (f, &pThis->csp_index);
1685 qemu_put_buffer (f, pThis->csp_reg83, 4);
1686 qemu_put_be32 (f, pThis->csp_reg83r);
1687 qemu_put_be32 (f, pThis->csp_reg83w);
1688
1689 qemu_put_buffer (f, pThis->in2_data, sizeof (pThis->in2_data));
1690 qemu_put_buffer (f, pThis->out_data, sizeof (pThis->out_data));
1691 qemu_put_8s (f, &pThis->test_reg);
1692 qemu_put_8s (f, &pThis->last_read_byte);
1693
1694 qemu_put_be32 (f, pThis->nzero);
1695 qemu_put_be32 (f, pThis->left_till_irq);
1696 qemu_put_be32 (f, pThis->dma_running);
1697 qemu_put_be32 (f, pThis->bytes_per_second);
1698 qemu_put_be32 (f, pThis->align);
1699
1700 qemu_put_be32 (f, pThis->mixer_nreg);
1701 qemu_put_buffer (f, pThis->mixer_regs, 256);
1702}
1703
1704static int SB_load (QEMUFile *f, void *opaque, int version_id)
1705{
1706#ifndef VBOX
1707 PSB16STATE pThis = opaque;
1708
1709 if (version_id != 1) {
1710 return -EINVAL;
1711 }
1712#else
1713 PSB16STATE pThis = (SB16STATE *)opaque;
1714#endif
1715
1716 pThis->irq=qemu_get_be32 (f);
1717 pThis->dma=qemu_get_be32 (f);
1718 pThis->hdma=qemu_get_be32 (f);
1719 pThis->port=qemu_get_be32 (f);
1720 pThis->ver=qemu_get_be32 (f);
1721 pThis->in_index=qemu_get_be32 (f);
1722 pThis->out_data_len=qemu_get_be32 (f);
1723 pThis->fmt_stereo=qemu_get_be32 (f);
1724 pThis->fmt_signed=qemu_get_be32 (f);
1725 pThis->fmt_bits=qemu_get_be32 (f);
1726 qemu_get_be32s (f, (uint32_t*)&pThis->fmt);
1727 pThis->dma_auto=qemu_get_be32 (f);
1728 pThis->block_size=qemu_get_be32 (f);
1729 pThis->fifo=qemu_get_be32 (f);
1730 pThis->freq=qemu_get_be32 (f);
1731 pThis->time_const=qemu_get_be32 (f);
1732 pThis->speaker=qemu_get_be32 (f);
1733 pThis->needed_bytes=qemu_get_be32 (f);
1734 pThis->cmd=qemu_get_be32 (f);
1735 pThis->use_hdma=qemu_get_be32 (f);
1736 pThis->highspeed=qemu_get_be32 (f);
1737 pThis->can_write=qemu_get_be32 (f);
1738 pThis->v2x6=qemu_get_be32 (f);
1739
1740 qemu_get_8s (f, &pThis->csp_param);
1741 qemu_get_8s (f, &pThis->csp_value);
1742 qemu_get_8s (f, &pThis->csp_mode);
1743 qemu_get_8s (f, &pThis->csp_param);
1744 qemu_get_buffer (f, pThis->csp_regs, 256);
1745 qemu_get_8s (f, &pThis->csp_index);
1746 qemu_get_buffer (f, pThis->csp_reg83, 4);
1747 pThis->csp_reg83r=qemu_get_be32 (f);
1748 pThis->csp_reg83w=qemu_get_be32 (f);
1749
1750 qemu_get_buffer (f, pThis->in2_data, sizeof (pThis->in2_data));
1751 qemu_get_buffer (f, pThis->out_data, sizeof (pThis->out_data));
1752 qemu_get_8s (f, &pThis->test_reg);
1753 qemu_get_8s (f, &pThis->last_read_byte);
1754
1755 pThis->nzero=qemu_get_be32 (f);
1756 pThis->left_till_irq=qemu_get_be32 (f);
1757 pThis->dma_running=qemu_get_be32 (f);
1758 pThis->bytes_per_second=qemu_get_be32 (f);
1759 pThis->align=qemu_get_be32 (f);
1760
1761 pThis->mixer_nreg=qemu_get_be32 (f);
1762 qemu_get_buffer (f, pThis->mixer_regs, 256);
1763
1764#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1765 if (pThis->pGstStrmOut)
1766 {
1767 pThis->pDrv->pfnCloseOut(pThis->pDrv, pThis->pGstStrmOut);
1768 pThis->pGstStrmOut = NULL;
1769 }
1770#else
1771 AUD_close_out (&pThis->card, pThis->voice);
1772 pThis->voice = NULL;
1773#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1774
1775 if (pThis->dma_running)
1776 {
1777 if (pThis->freq)
1778 {
1779 pThis->audio_free = 0;
1780
1781#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1782 PDMAUDIOSTREAMCFG streamCfg;
1783 streamCfg.uHz = pThis->freq;
1784 streamCfg.cChannels = 1 << pThis->fmt_stereo;
1785 streamCfg.enmFormat = pThis->fmt;
1786 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANESS;
1787
1788 int rc = pThis->pDrv->pfnOpenOut(pThis->pDrv, "sb16.out", &streamCfg, &pThis->pGstStrmOut);
1789 AssertRC(rc);
1790#else
1791 audsettings_t as;
1792 as.freq = pThis->freq;
1793 as.nchannels = 1 << pThis->fmt_stereo;
1794 as.fmt = pThis->fmt;
1795 as.endianness = 0;
1796 pThis->voice = AUD_open_out (
1797 &pThis->card,
1798 pThis->voice,
1799 "sb16",
1800 pThis,
1801 sb16AudioCallback,
1802 &as
1803 );
1804#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1805 }
1806
1807 control(pThis, 1);
1808 speaker(pThis, pThis->speaker);
1809 }
1810
1811#ifdef VBOX
1812 return VINF_SUCCESS;
1813#endif
1814}
1815
1816#ifndef VBOX
1817int SB16_init (AudioState *audio, qemu_irq *pic)
1818{
1819 PSB16STATE pThis;
1820 int i;
1821 static const uint8_t dsp_write_ports[] = {0x6, 0xc};
1822 static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};
1823
1824 if (!audio) {
1825 LogFlowFunc(("No audio state\n"));
1826 return -1;
1827 }
1828
1829 s = qemu_mallocz (sizeof (*s));
1830 if (!s) {
1831 LogFlowFunc(("Could not allocate memory for SB16 (%zu bytes)\n",
1832 sizeof (*s));
1833 return -1;
1834 }
1835
1836 pThis->cmd = -1;
1837 pThis->pic = pic;
1838 pThis->irq = conf.irq;
1839 pThis->dma = conf.dma;
1840 pThis->hdma = conf.hdma;
1841 pThis->port = conf.port;
1842 pThis->ver = conf.ver_lo | (conf.ver_hi << 8);
1843
1844 pThis->mixer_regs[0x80] = magic_of_irq (pThis->irq);
1845 pThis->mixer_regs[0x81] = (1 << pThis->dma) | (1 << pThis->hdma);
1846 pThis->mixer_regs[0x82] = 2 << 5;
1847
1848 pThis->csp_regs[5] = 1;
1849 pThis->csp_regs[9] = 0xf8;
1850
1851 reset_mixer (pThis);
1852 pThis->aux_ts = qemu_new_timer (vm_clock, aux_timer, s);
1853 if (!pThis->aux_ts) {
1854 LogFlowFunc(("warning: Could not create auxiliary timer\n"));
1855 }
1856
1857 for (i = 0; i < LENOFA (dsp_write_ports); i++) {
1858 register_ioport_write (pThis->port + dsp_write_ports[i], 1, 1, dsp_write, s);
1859 }
1860
1861 for (i = 0; i < LENOFA (dsp_read_ports); i++) {
1862 register_ioport_read (pThis->port + dsp_read_ports[i], 1, 1, dsp_read, s);
1863 }
1864
1865 register_ioport_write (pThis->port + 0x4, 1, 1, mixer_write_indexb, s);
1866 register_ioport_write (pThis->port + 0x4, 1, 2, mixer_write_indexw, s);
1867 register_ioport_read (pThis->port + 0x5, 1, 1, mixer_read, s);
1868 register_ioport_write (pThis->port + 0x5, 1, 1, mixer_write_datab, s);
1869
1870 DMA_register_channel (pThis->hdma, SB_read_DMA, s);
1871 DMA_register_channel (pThis->dma, SB_read_DMA, s);
1872 pThis->can_write = 1;
1873
1874 register_savevm ("sb16", 0, 1, SB_save, SB_load, s);
1875 AUD_register_card (audio, "sb16", &pThis->card);
1876 return 0;
1877}
1878
1879#else /* VBOX */
1880
1881
1882static DECLCALLBACK(int) sb16LiveExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1883{
1884 PSB16STATE pThis = PDMINS_2_DATA (pDevIns, PSB16STATE);
1885
1886 SSMR3PutS32(pSSM, pThis->irqCfg);
1887 SSMR3PutS32(pSSM, pThis->dmaCfg);
1888 SSMR3PutS32(pSSM, pThis->hdmaCfg);
1889 SSMR3PutS32(pSSM, pThis->portCfg);
1890 SSMR3PutS32(pSSM, pThis->verCfg);
1891 return VINF_SSM_DONT_CALL_AGAIN;
1892}
1893
1894static DECLCALLBACK(int) sb16SaveExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1895{
1896 PSB16STATE pThis = PDMINS_2_DATA (pDevIns, PSB16STATE);
1897
1898 sb16LiveExec (pDevIns, pSSM, 0);
1899 SB_save (pSSM, pThis);
1900 return VINF_SUCCESS;
1901}
1902
1903static DECLCALLBACK(int) sb16LoadExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSM,
1904 uint32_t uVersion, uint32_t uPass)
1905{
1906 PSB16STATE pThis = PDMINS_2_DATA (pDevIns, PSB16STATE);
1907
1908 AssertMsgReturn( uVersion == SB16_SAVE_STATE_VERSION
1909 || uVersion == SB16_SAVE_STATE_VERSION_VBOX_30,
1910 ("%u\n", uVersion),
1911 VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
1912 if (uVersion > SB16_SAVE_STATE_VERSION_VBOX_30)
1913 {
1914 int32_t irq;
1915 SSMR3GetS32 (pSSM, &irq);
1916 int32_t dma;
1917 SSMR3GetS32 (pSSM, &dma);
1918 int32_t hdma;
1919 SSMR3GetS32 (pSSM, &hdma);
1920 int32_t port;
1921 SSMR3GetS32 (pSSM, &port);
1922 int32_t ver;
1923 int rc = SSMR3GetS32 (pSSM, &ver);
1924 AssertRCReturn (rc, rc);
1925
1926 if ( irq != pThis->irqCfg
1927 || dma != pThis->dmaCfg
1928 || hdma != pThis->hdmaCfg
1929 || port != pThis->portCfg
1930 || ver != pThis->verCfg )
1931 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
1932 N_("config changed: irq=%x/%x dma=%x/%x hdma=%x/%x port=%x/%x ver=%x/%x (saved/config)"),
1933 irq, pThis->irqCfg,
1934 dma, pThis->dmaCfg,
1935 hdma, pThis->hdmaCfg,
1936 port, pThis->portCfg,
1937 ver, pThis->verCfg);
1938 }
1939 if (uPass != SSM_PASS_FINAL)
1940 return VINF_SUCCESS;
1941
1942 SB_load(pSSM, pThis, uVersion);
1943 return VINF_SUCCESS;
1944}
1945
1946/**
1947 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1948 */
1949static DECLCALLBACK(void *) sb16QueryInterface (struct PDMIBASE *pInterface,
1950 const char *pszIID)
1951{
1952 PSB16STATE pThis = RT_FROM_MEMBER(pInterface, SB16STATE, IBase);
1953 Assert(&pThis->IBase == pInterface);
1954
1955 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
1956 return NULL;
1957}
1958
1959/**
1960 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1961 */
1962static DECLCALLBACK(int) sb16Destruct(PPDMDEVINS pDevIns)
1963{
1964 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1965
1966#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1967 PSB16DRIVER pDrv;
1968
1969 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1970 pDrv->Out.phStrmOut = NULL;
1971
1972 pThis->pSinkOutput = NULL;
1973
1974 if (pThis->pMixer)
1975 {
1976 audioMixerDestroy(pThis->pMixer);
1977 pThis->pMixer = NULL;
1978 }
1979#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1980
1981 return VINF_SUCCESS;
1982}
1983
1984static DECLCALLBACK(int) sb16Construct (PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1985{
1986 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1987 int rc;
1988
1989 /*
1990 * Validations.
1991 */
1992 Assert(iInstance == 0);
1993 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1994 if (!CFGMR3AreValuesValid(pCfgHandle,
1995 "IRQ\0"
1996 "DMA\0"
1997 "DMA16\0"
1998 "Port\0"
1999 "Version\0"))
2000 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2001 N_("Invalid configuration for sb16 device"));
2002
2003 /*
2004 * Read config data.
2005 */
2006 rc = CFGMR3QuerySIntDef(pCfgHandle, "IRQ", &pThis->irq, 5);
2007 if (RT_FAILURE(rc))
2008 return PDMDEV_SET_ERROR(pDevIns, rc,
2009 N_("Configuration error: Failed to get the \"IRQ\" value"));
2010 pThis->irqCfg = pThis->irq;
2011
2012 rc = CFGMR3QuerySIntDef(pCfgHandle, "DMA", &pThis->dma, 1);
2013 if (RT_FAILURE(rc))
2014 return PDMDEV_SET_ERROR(pDevIns, rc,
2015 N_("Configuration error: Failed to get the \"DMA\" value"));
2016 pThis->dmaCfg = pThis->dma;
2017
2018 rc = CFGMR3QuerySIntDef(pCfgHandle, "DMA16", &pThis->hdma, 5);
2019 if (RT_FAILURE(rc))
2020 return PDMDEV_SET_ERROR(pDevIns, rc,
2021 N_("Configuration error: Failed to get the \"DMA16\" value"));
2022 pThis->hdmaCfg = pThis->hdma;
2023
2024 RTIOPORT Port;
2025 rc = CFGMR3QueryPortDef(pCfgHandle, "Port", &Port, 0x220);
2026 if (RT_FAILURE(rc))
2027 return PDMDEV_SET_ERROR(pDevIns, rc,
2028 N_("Configuration error: Failed to get the \"Port\" value"));
2029 pThis->port = Port;
2030 pThis->portCfg = Port;
2031
2032 uint16_t u16Version;
2033 rc = CFGMR3QueryU16Def(pCfgHandle, "Version", &u16Version, 0x0405);
2034 if (RT_FAILURE(rc))
2035 return PDMDEV_SET_ERROR(pDevIns, rc,
2036 N_("Configuration error: Failed to get the \"Version\" value"));
2037 pThis->ver = u16Version;
2038 pThis->verCfg = u16Version;
2039
2040 /*
2041 * Init instance data.
2042 */
2043 pThis->pDevIns = pDevIns;
2044 pThis->IBase.pfnQueryInterface = sb16QueryInterface;
2045 pThis->cmd = -1;
2046
2047 pThis->mixer_regs[0x80] = magic_of_irq (pThis->irq);
2048 pThis->mixer_regs[0x81] = (1 << pThis->dma) | (1 << pThis->hdma);
2049 pThis->mixer_regs[0x82] = 2 << 5;
2050
2051 pThis->csp_regs[5] = 1;
2052 pThis->csp_regs[9] = 0xf8;
2053
2054 reset_mixer(pThis);
2055
2056 /*
2057 * Create timer, register & attach stuff.
2058 */
2059 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16Timer, pThis,
2060 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 timer", &pThis->pTimer);
2061 if (RT_FAILURE(rc))
2062 AssertMsgFailedReturn(("pfnTMTimerCreate -> %Rrc\n", rc), rc);
2063
2064 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x04, 2, pThis,
2065 mixer_write, mixer_read, NULL, NULL, "SB16");
2066 if (RT_FAILURE(rc))
2067 return rc;
2068 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x06, 10, pThis,
2069 dsp_write, dsp_read, NULL, NULL, "SB16");
2070 if (RT_FAILURE(rc))
2071 return rc;
2072
2073 rc = PDMDevHlpDMARegister(pDevIns, pThis->hdma, SB_read_DMA, pThis);
2074 if (RT_FAILURE(rc))
2075 return rc;
2076 rc = PDMDevHlpDMARegister(pDevIns, pThis->dma, SB_read_DMA, pThis);
2077 if (RT_FAILURE(rc))
2078 return rc;
2079
2080 pThis->can_write = 1;
2081
2082 rc = PDMDevHlpSSMRegister3(pDevIns, SB16_SAVE_STATE_VERSION, sizeof(SB16STATE), sb16LiveExec, sb16SaveExec, sb16LoadExec);
2083 if (RT_FAILURE(rc))
2084 return rc;
2085
2086 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Audio Driver Port");
2087#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2088 if(RT_SUCCESS(rc))
2089 {
2090 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIAUDIOCONNECTOR);
2091 AssertMsgReturn(pThis->pDrv,
2092 ("Configuration error: instance %d has no host audio interface!\n", iInstance),
2093 VERR_PDM_MISSING_INTERFACE);
2094 }
2095 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2096#else
2097 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2098#endif
2099 LogFunc(("No attached driver!\n"));
2100 else if (RT_FAILURE(rc))
2101 {
2102 AssertMsgFailed(("Failed to attach AC97 LUN #0! rc=%Rrc\n", rc));
2103 return rc;
2104 }
2105
2106#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2107 legacy_reset(pThis);
2108
2109 if (!pThis->pDrv->pfnIsOutputOK(pThis->pDrv,pThis->pGstStrmOut))
2110 {
2111 LogRel(("SB16: WARNING: Unable to open PCM OUT!\n"));
2112 pThis->pDrv->pfnCloseOut(pThis->pDrv, pThis->pGstStrmOut );
2113 pThis->pGstStrmOut = NULL;
2114
2115 pThis->pDrv->pfnInitNull(pThis->pDrv);
2116
2117 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2118 N_("No audio devices could be opened. Selecting the NULL audio backend "
2119 "with the consequence that no sound is audible"));
2120 }
2121#else
2122 AUD_register_card("sb16", &pThis->card);
2123 legacy_reset(pThis);
2124
2125 if (!AUD_is_host_voice_out_ok(pThis->voice))
2126 {
2127 LogRel (("SB16: WARNING: Unable to open PCM OUT!\n"));
2128 AUD_close_out (&pThis->card, pThis->voice);
2129 pThis->voice = NULL;
2130
2131 AUD_init_null();
2132
2133 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2134 N_("No audio devices could be opened. Selecting the NULL audio backend "
2135 "with the consequence that no sound is audible"));
2136 }
2137#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2138
2139 return VINF_SUCCESS;
2140}
2141
2142const PDMDEVREG g_DeviceSB16 =
2143{
2144 /* u32Version */
2145 PDM_DEVREG_VERSION,
2146 /* szName */
2147 "sb16",
2148 /* szRCMod */
2149 "",
2150 /* szR0Mod */
2151 "",
2152 /* pszDescription */
2153 "Sound Blaster 16 Controller",
2154 /* fFlags */
2155 PDM_DEVREG_FLAGS_DEFAULT_BITS,
2156 /* fClass */
2157 PDM_DEVREG_CLASS_AUDIO,
2158 /* cMaxInstances */
2159 1,
2160 /* cbInstance */
2161 sizeof(SB16STATE),
2162 /* pfnConstruct */
2163 sb16Construct,
2164 /* pfnDestruct */
2165 sb16Destruct,
2166 /* pfnRelocate */
2167 NULL,
2168 /* pfnMemSetup */
2169 NULL,
2170 /* pfnPowerOn */
2171 NULL,
2172 /* pfnReset */
2173 NULL,
2174 /* pfnSuspend */
2175 NULL,
2176 /* pfnResume */
2177 NULL,
2178 /* pfnAttach */
2179 NULL,
2180 /* pfnDetach */
2181 NULL,
2182 /* pfnQueryInterface */
2183 NULL,
2184 /* pfnInitComplete */
2185 NULL,
2186 /* pfnPowerOff */
2187 NULL,
2188 /* pfnSoftReset */
2189 NULL,
2190 /* u32VersionEnd */
2191 PDM_DEVREG_VERSION
2192};
2193
2194#endif /* VBOX */
2195
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