VirtualBox

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

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

SB16: Clear interupt flags properly.

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