VirtualBox

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

Last change on this file since 21848 was 20087, checked in by vboxsync, 15 years ago

TM,*: Proper timer callback locking and pvUser for devices.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.3 KB
Line 
1/* $Id: DevSB16.cpp 20087 2009-05-27 14:31:18Z 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, void *pvThis)
283{
284 SB16State *s = (SB16State *)pvThis;
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 size_t to_copy;
1364#else
1365 uint32_t copied;
1366 uint32_t to_copy;
1367#endif
1368
1369 to_copy = audio_MIN (temp, left);
1370 if (to_copy > sizeof (tmpbuf)) {
1371 to_copy = sizeof (tmpbuf);
1372 }
1373
1374#ifndef VBOX
1375 copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
1376#else
1377 int rc = PDMDevHlpDMAReadMemory(s->pDevIns, nchan, tmpbuf, dma_pos,
1378 to_copy, &copied);
1379 AssertMsgRC (rc, ("DMAReadMemory -> %Rrc\n", rc));
1380#endif
1381
1382 copied = AUD_write (s->voice, tmpbuf, copied);
1383
1384 temp -= copied;
1385 dma_pos = (dma_pos + copied) % dma_len;
1386 net += copied;
1387
1388 if (!copied) {
1389 break;
1390 }
1391 }
1392
1393 return net;
1394}
1395
1396#ifndef VBOX
1397static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
1398#else
1399static DECLCALLBACK(uint32_t) SB_read_DMA (PPDMDEVINS pDevIns, void *opaque, unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
1400#endif
1401{
1402 SB16State *s = (SB16State*)opaque;
1403 int till, copy, written, free;
1404
1405 if (s->block_size <= 0) {
1406 dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
1407 s->block_size, nchan, dma_pos, dma_len);
1408 return dma_pos;
1409 }
1410
1411 if (s->left_till_irq < 0) {
1412 s->left_till_irq = s->block_size;
1413 }
1414
1415 if (s->voice) {
1416 free = s->audio_free & ~s->align;
1417 if ((free <= 0) || !dma_len) {
1418 return dma_pos;
1419 }
1420 }
1421 else {
1422 free = dma_len;
1423 }
1424
1425 copy = free;
1426 till = s->left_till_irq;
1427
1428#ifdef DEBUG_SB16_MOST
1429 dolog ("pos:%06d %d till:%d len:%d\n",
1430 dma_pos, free, till, dma_len);
1431#endif
1432
1433 if (till <= copy) {
1434 if (0 == s->dma_auto) {
1435 copy = till;
1436 }
1437 }
1438
1439 written = write_audio (s, nchan, dma_pos, dma_len, copy);
1440 dma_pos = (dma_pos + written) % dma_len;
1441 s->left_till_irq -= written;
1442
1443 if (s->left_till_irq <= 0) {
1444 s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
1445#ifndef VBOX
1446 qemu_irq_raise (s->pic[s->irq]);
1447#else
1448 PDMDevHlpISASetIrq(s->pDevIns, s->irq, 1);
1449#endif
1450 if (0 == s->dma_auto) {
1451 control (s, 0);
1452 speaker (s, 0);
1453 }
1454 }
1455
1456#ifdef DEBUG_SB16_MOST
1457 ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
1458 dma_pos, free, dma_len, s->left_till_irq, copy, written,
1459 s->block_size);
1460#endif
1461
1462 while (s->left_till_irq <= 0) {
1463 s->left_till_irq = s->block_size + s->left_till_irq;
1464 }
1465
1466 return dma_pos;
1467}
1468
1469static void SB_audio_callback (void *opaque, int free)
1470{
1471 SB16State *s = (SB16State*)opaque;
1472 s->audio_free = free;
1473#ifdef VBOX
1474 /* New space available, see if we can transfer more. There is no cyclic DMA timer in VBox. */
1475 PDMDevHlpDMASchedule (s->pDevIns);
1476#endif
1477}
1478
1479#ifndef VBOX
1480static void SB_save (QEMUFile *f, void *opaque)
1481{
1482 SB16State *s = opaque;
1483#else
1484static DECLCALLBACK(int) SaveExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1485{
1486 SB16State *s = PDMINS_2_DATA (pDevIns, SB16State *);
1487 QEMUFile *f = pSSMHandle;
1488#endif
1489
1490 qemu_put_be32 (f, s->irq);
1491 qemu_put_be32 (f, s->dma);
1492 qemu_put_be32 (f, s->hdma);
1493 qemu_put_be32 (f, s->port);
1494 qemu_put_be32 (f, s->ver);
1495 qemu_put_be32 (f, s->in_index);
1496 qemu_put_be32 (f, s->out_data_len);
1497 qemu_put_be32 (f, s->fmt_stereo);
1498 qemu_put_be32 (f, s->fmt_signed);
1499 qemu_put_be32 (f, s->fmt_bits);
1500 qemu_put_be32s (f, &s->fmt);
1501 qemu_put_be32 (f, s->dma_auto);
1502 qemu_put_be32 (f, s->block_size);
1503 qemu_put_be32 (f, s->fifo);
1504 qemu_put_be32 (f, s->freq);
1505 qemu_put_be32 (f, s->time_const);
1506 qemu_put_be32 (f, s->speaker);
1507 qemu_put_be32 (f, s->needed_bytes);
1508 qemu_put_be32 (f, s->cmd);
1509 qemu_put_be32 (f, s->use_hdma);
1510 qemu_put_be32 (f, s->highspeed);
1511 qemu_put_be32 (f, s->can_write);
1512 qemu_put_be32 (f, s->v2x6);
1513
1514 qemu_put_8s (f, &s->csp_param);
1515 qemu_put_8s (f, &s->csp_value);
1516 qemu_put_8s (f, &s->csp_mode);
1517 qemu_put_8s (f, &s->csp_param);
1518 qemu_put_buffer (f, s->csp_regs, 256);
1519 qemu_put_8s (f, &s->csp_index);
1520 qemu_put_buffer (f, s->csp_reg83, 4);
1521 qemu_put_be32 (f, s->csp_reg83r);
1522 qemu_put_be32 (f, s->csp_reg83w);
1523
1524 qemu_put_buffer (f, s->in2_data, sizeof (s->in2_data));
1525 qemu_put_buffer (f, s->out_data, sizeof (s->out_data));
1526 qemu_put_8s (f, &s->test_reg);
1527 qemu_put_8s (f, &s->last_read_byte);
1528
1529 qemu_put_be32 (f, s->nzero);
1530 qemu_put_be32 (f, s->left_till_irq);
1531 qemu_put_be32 (f, s->dma_running);
1532 qemu_put_be32 (f, s->bytes_per_second);
1533 qemu_put_be32 (f, s->align);
1534
1535 qemu_put_be32 (f, s->mixer_nreg);
1536 qemu_put_buffer (f, s->mixer_regs, 256);
1537
1538#ifdef VBOX
1539 return VINF_SUCCESS;
1540#endif
1541}
1542
1543#ifndef VBOX
1544static int SB_load (QEMUFile *f, void *opaque, int version_id)
1545{
1546 SB16State *s = opaque;
1547
1548 if (version_id != 1) {
1549 return -EINVAL;
1550 }
1551#else /* VBOX */
1552static DECLCALLBACK(int) LoadExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle,
1553 uint32_t u32Version)
1554{
1555 SB16State *s = PDMINS_2_DATA (pDevIns, SB16State *);
1556 QEMUFile *f = pSSMHandle;
1557
1558 if (u32Version != SB16_SSM_VERSION)
1559 {
1560 AssertMsgFailed(("u32Version=%d\n", u32Version));
1561 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1562 }
1563#endif /* VBOX */
1564
1565 s->irq=qemu_get_be32 (f);
1566 s->dma=qemu_get_be32 (f);
1567 s->hdma=qemu_get_be32 (f);
1568 s->port=qemu_get_be32 (f);
1569 s->ver=qemu_get_be32 (f);
1570 s->in_index=qemu_get_be32 (f);
1571 s->out_data_len=qemu_get_be32 (f);
1572 s->fmt_stereo=qemu_get_be32 (f);
1573 s->fmt_signed=qemu_get_be32 (f);
1574 s->fmt_bits=qemu_get_be32 (f);
1575 qemu_get_be32s (f, (uint32_t*)&s->fmt);
1576 s->dma_auto=qemu_get_be32 (f);
1577 s->block_size=qemu_get_be32 (f);
1578 s->fifo=qemu_get_be32 (f);
1579 s->freq=qemu_get_be32 (f);
1580 s->time_const=qemu_get_be32 (f);
1581 s->speaker=qemu_get_be32 (f);
1582 s->needed_bytes=qemu_get_be32 (f);
1583 s->cmd=qemu_get_be32 (f);
1584 s->use_hdma=qemu_get_be32 (f);
1585 s->highspeed=qemu_get_be32 (f);
1586 s->can_write=qemu_get_be32 (f);
1587 s->v2x6=qemu_get_be32 (f);
1588
1589 qemu_get_8s (f, &s->csp_param);
1590 qemu_get_8s (f, &s->csp_value);
1591 qemu_get_8s (f, &s->csp_mode);
1592 qemu_get_8s (f, &s->csp_param);
1593 qemu_get_buffer (f, s->csp_regs, 256);
1594 qemu_get_8s (f, &s->csp_index);
1595 qemu_get_buffer (f, s->csp_reg83, 4);
1596 s->csp_reg83r=qemu_get_be32 (f);
1597 s->csp_reg83w=qemu_get_be32 (f);
1598
1599 qemu_get_buffer (f, s->in2_data, sizeof (s->in2_data));
1600 qemu_get_buffer (f, s->out_data, sizeof (s->out_data));
1601 qemu_get_8s (f, &s->test_reg);
1602 qemu_get_8s (f, &s->last_read_byte);
1603
1604 s->nzero=qemu_get_be32 (f);
1605 s->left_till_irq=qemu_get_be32 (f);
1606 s->dma_running=qemu_get_be32 (f);
1607 s->bytes_per_second=qemu_get_be32 (f);
1608 s->align=qemu_get_be32 (f);
1609
1610 s->mixer_nreg=qemu_get_be32 (f);
1611 qemu_get_buffer (f, s->mixer_regs, 256);
1612
1613 if (s->voice) {
1614 AUD_close_out (&s->card, s->voice);
1615 s->voice = NULL;
1616 }
1617
1618 if (s->dma_running) {
1619 if (s->freq) {
1620 audsettings_t as;
1621
1622 s->audio_free = 0;
1623
1624 as.freq = s->freq;
1625 as.nchannels = 1 << s->fmt_stereo;
1626 as.fmt = s->fmt;
1627 as.endianness = 0;
1628
1629 s->voice = AUD_open_out (
1630 &s->card,
1631 s->voice,
1632 "sb16",
1633 s,
1634 SB_audio_callback,
1635 &as
1636 );
1637 }
1638
1639 control (s, 1);
1640 speaker (s, s->speaker);
1641 }
1642
1643#ifdef VBOX
1644 return VINF_SUCCESS;
1645#endif
1646}
1647
1648#ifndef VBOX
1649int SB16_init (AudioState *audio, qemu_irq *pic)
1650{
1651 SB16State *s;
1652 int i;
1653 static const uint8_t dsp_write_ports[] = {0x6, 0xc};
1654 static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};
1655
1656 if (!audio) {
1657 dolog ("No audio state\n");
1658 return -1;
1659 }
1660
1661 s = qemu_mallocz (sizeof (*s));
1662 if (!s) {
1663 dolog ("Could not allocate memory for SB16 (%zu bytes)\n",
1664 sizeof (*s));
1665 return -1;
1666 }
1667
1668 s->cmd = -1;
1669 s->pic = pic;
1670 s->irq = conf.irq;
1671 s->dma = conf.dma;
1672 s->hdma = conf.hdma;
1673 s->port = conf.port;
1674 s->ver = conf.ver_lo | (conf.ver_hi << 8);
1675
1676 s->mixer_regs[0x80] = magic_of_irq (s->irq);
1677 s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
1678 s->mixer_regs[0x82] = 2 << 5;
1679
1680 s->csp_regs[5] = 1;
1681 s->csp_regs[9] = 0xf8;
1682
1683 reset_mixer (s);
1684 s->aux_ts = qemu_new_timer (vm_clock, aux_timer, s);
1685 if (!s->aux_ts) {
1686 dolog ("warning: Could not create auxiliary timer\n");
1687 }
1688
1689 for (i = 0; i < LENOFA (dsp_write_ports); i++) {
1690 register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s);
1691 }
1692
1693 for (i = 0; i < LENOFA (dsp_read_ports); i++) {
1694 register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s);
1695 }
1696
1697 register_ioport_write (s->port + 0x4, 1, 1, mixer_write_indexb, s);
1698 register_ioport_write (s->port + 0x4, 1, 2, mixer_write_indexw, s);
1699 register_ioport_read (s->port + 0x5, 1, 1, mixer_read, s);
1700 register_ioport_write (s->port + 0x5, 1, 1, mixer_write_datab, s);
1701
1702 DMA_register_channel (s->hdma, SB_read_DMA, s);
1703 DMA_register_channel (s->dma, SB_read_DMA, s);
1704 s->can_write = 1;
1705
1706 register_savevm ("sb16", 0, 1, SB_save, SB_load, s);
1707 AUD_register_card (audio, "sb16", &s->card);
1708 return 0;
1709}
1710
1711#else /* VBOX */
1712
1713static DECLCALLBACK(void *) sb16QueryInterface (struct PDMIBASE *pInterface,
1714 PDMINTERFACE enmInterface)
1715{
1716 SB16State *pThis = (SB16State *)((uintptr_t)pInterface
1717 - RT_OFFSETOF(SB16State, IBase));
1718 Assert(&pThis->IBase == pInterface);
1719 switch (enmInterface)
1720 {
1721 case PDMINTERFACE_BASE:
1722 return &pThis->IBase;
1723 default:
1724 return NULL;
1725 }
1726}
1727
1728static DECLCALLBACK(int) sb16Construct (PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1729{
1730 SB16State *s = PDMINS_2_DATA(pDevIns, SB16State *);
1731 int rc;
1732
1733 /*
1734 * Validations.
1735 */
1736 Assert(iInstance == 0);
1737 if (!CFGMR3AreValuesValid(pCfgHandle,
1738 "IRQ\0"
1739 "DMA\0"
1740 "DMA16\0"
1741 "Port\0"
1742 "Version\0"))
1743 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1744 N_("Invalid configuraton for sb16 device"));
1745
1746 /*
1747 * Read config data.
1748 */
1749 rc = CFGMR3QuerySIntDef(pCfgHandle, "IRQ", &s->irq, 5);
1750 if (RT_FAILURE(rc))
1751 return PDMDEV_SET_ERROR(pDevIns, rc,
1752 N_("Configuration error: Failed to get the \"IRQ\" value"));
1753
1754 rc = CFGMR3QuerySIntDef(pCfgHandle, "DMA", &s->dma, 1);
1755 if (RT_FAILURE(rc))
1756 return PDMDEV_SET_ERROR(pDevIns, rc,
1757 N_("Configuration error: Failed to get the \"DMA\" value"));
1758
1759 rc = CFGMR3QuerySIntDef(pCfgHandle, "DMA16", &s->hdma, 5);
1760 if (RT_FAILURE(rc))
1761 return PDMDEV_SET_ERROR(pDevIns, rc,
1762 N_("Configuration error: Failed to get the \"DMA16\" value"));
1763
1764 RTIOPORT Port;
1765 rc = CFGMR3QueryPortDef(pCfgHandle, "Port", &Port, 0x220);
1766 if (RT_FAILURE(rc))
1767 return PDMDEV_SET_ERROR(pDevIns, rc,
1768 N_("Configuration error: Failed to get the \"Port\" value"));
1769 s->port = Port;
1770
1771 uint16_t u16Version;
1772 rc = CFGMR3QueryU16Def(pCfgHandle, "Version", &u16Version, 0x0405);
1773 if (RT_FAILURE(rc))
1774 return PDMDEV_SET_ERROR(pDevIns, rc,
1775 N_("Configuration error: Failed to get the \"Version\" value"));
1776 s->ver = u16Version;
1777
1778 /*
1779 * Init instance data.
1780 */
1781 s->pDevIns = pDevIns;
1782 s->IBase.pfnQueryInterface = sb16QueryInterface;
1783 s->cmd = -1;
1784
1785 s->mixer_regs[0x80] = magic_of_irq (s->irq);
1786 s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
1787 s->mixer_regs[0x82] = 2 << 5;
1788
1789 s->csp_regs[5] = 1;
1790 s->csp_regs[9] = 0xf8;
1791
1792 reset_mixer(s);
1793
1794 /*
1795 * Create timer, register & attach stuff.
1796 */
1797 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16Timer, s,
1798 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 timer", &s->pTimer);
1799 if (RT_FAILURE(rc))
1800 AssertMsgFailedReturn(("pfnTMTimerCreate -> %Rrc\n", rc), rc);
1801
1802 rc = PDMDevHlpIOPortRegister(pDevIns, s->port + 0x04, 2, s,
1803 mixer_write, mixer_read, NULL, NULL, "SB16");
1804 if (RT_FAILURE(rc))
1805 return rc;
1806 rc = PDMDevHlpIOPortRegister(pDevIns, s->port + 0x06, 10, s,
1807 dsp_write, dsp_read, NULL, NULL, "SB16");
1808 if (RT_FAILURE(rc))
1809 return rc;
1810
1811 rc = PDMDevHlpDMARegister(pDevIns, s->hdma, SB_read_DMA, s);
1812 if (RT_FAILURE(rc))
1813 return rc;
1814 rc = PDMDevHlpDMARegister(pDevIns, s->dma, SB_read_DMA, s);
1815 if (RT_FAILURE(rc))
1816 return rc;
1817
1818 s->can_write = 1;
1819
1820 rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance, SB16_SSM_VERSION,
1821 sizeof(*s), NULL, SaveExec, NULL, NULL, LoadExec, NULL);
1822 if (RT_FAILURE(rc))
1823 return rc;
1824
1825 rc = PDMDevHlpDriverAttach(pDevIns, 0, &s->IBase, &s->pDrvBase, "Audio Driver Port");
1826 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1827 Log(("sb16: No attached driver!\n"));
1828 else if (RT_FAILURE(rc))
1829 AssertMsgFailedReturn(("Failed to attach SB16 LUN #0! rc=%Rrc\n", rc), rc);
1830
1831 AUD_register_card("sb16", &s->card);
1832 legacy_reset(s);
1833
1834 if (!s->voice)
1835 {
1836 AUD_close_out(&s->card, s->voice);
1837 s->voice = NULL;
1838 AUD_init_null();
1839 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
1840 N_("No audio devices could be opened. Selecting the NULL audio backend "
1841 "with the consequence that no sound is audible"));
1842 }
1843 return VINF_SUCCESS;
1844}
1845
1846const PDMDEVREG g_DeviceSB16 =
1847{
1848 /* u32Version */
1849 PDM_DEVREG_VERSION,
1850 /* szDeviceName */
1851 "sb16",
1852 /* szRCMod */
1853 "",
1854 /* szR0Mod */
1855 "",
1856 /* pszDescription */
1857 "Sound Blaster 16 Controller",
1858 /* fFlags */
1859 PDM_DEVREG_FLAGS_DEFAULT_BITS,
1860 /* fClass */
1861 PDM_DEVREG_CLASS_AUDIO,
1862 /* cMaxInstances */
1863 1,
1864 /* cbInstance */
1865 sizeof(SB16State),
1866 /* pfnConstruct */
1867 sb16Construct,
1868 /* pfnDesctruct */
1869 NULL,
1870 /* pfnRelocate */
1871 NULL,
1872 /* pfnIOCtl */
1873 NULL,
1874 /* pfnPowerOn */
1875 NULL,
1876 /* pfnReset */
1877 NULL,
1878 /* pfnSuspend */
1879 NULL,
1880 /* pfnResume */
1881 NULL,
1882 /* pfnAttach */
1883 NULL,
1884 /* pfnDetach */
1885 NULL,
1886 /* pfnQueryInterface */
1887 NULL,
1888 /* pfnInitComplete */
1889 NULL,
1890 /* pfnPowerOff */
1891 NULL,
1892 /* pfnSoftReset */
1893 NULL,
1894 /* u32VersionEnd */
1895 PDM_DEVREG_VERSION
1896};
1897
1898#endif /* VBOX */
1899
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