VirtualBox

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

Last change on this file since 16684 was 12978, checked in by vboxsync, 16 years ago

PDM: PDM_DEVREG_FLAGS_DEFAULT_BITS convenience.

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