VirtualBox

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

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

PDM/Audio: Update.

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