VirtualBox

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

Last change on this file since 10764 was 9338, checked in by vboxsync, 17 years ago

comments

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