VirtualBox

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

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

Devices,VMM: Replaced all VERR_SSM_LOAD_CONFIG_MISMATCH returns with SSMR3SetCfgError calls.

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