VirtualBox

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

Last change on this file since 29743 was 26165, checked in by vboxsync, 15 years ago

PDM: s/szDeviceName/szName/g - PDMDEVREG & PDMUSBREG.

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