VirtualBox

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

Last change on this file since 9074 was 7882, checked in by vboxsync, 17 years ago

warnings

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