Blame view

hw/sb16.c 35.6 KB
1
2
/*
 * QEMU Soundblaster 16 emulation
3
4
5
 *
 * Copyright (c) 2003-2005 Vassili Karpov (malc)
 *
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
pbrook authored
24
25
26
27
28
#include "hw.h"
#include "audiodev.h"
#include "audio/audio.h"
#include "isa.h"
#include "qemu-timer.h"
29
30
#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
bellard authored
31
32
33
34

/* #define DEBUG */
/* #define DEBUG_SB16_MOST */
35
36
37
38
39
40
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
bellard authored
41
#define IO_READ_PROTO(name)                             \
bellard authored
42
    uint32_t name (void *opaque, uint32_t nport)
bellard authored
43
#define IO_WRITE_PROTO(name)                                    \
bellard authored
44
    void name (void *opaque, uint32_t nport, uint32_t val)
45
bellard authored
46
static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
bellard authored
47
48
49
50
51
52
53
54
static struct {
    int ver_lo;
    int ver_hi;
    int irq;
    int dma;
    int hdma;
    int port;
bellard authored
55
} conf = {5, 4, 5, 1, 5, 0x220};
56
57
typedef struct SB16State {
bellard authored
58
    QEMUSoundCard card;
pbrook authored
59
    qemu_irq *pic;
bellard authored
60
61
62
63
64
65
    int irq;
    int dma;
    int hdma;
    int port;
    int ver;
66
67
68
69
70
    int in_index;
    int out_data_len;
    int fmt_stereo;
    int fmt_signed;
    int fmt_bits;
bellard authored
71
    audfmt_e fmt;
72
    int dma_auto;
bellard authored
73
    int block_size;
74
75
76
77
78
79
80
    int fifo;
    int freq;
    int time_const;
    int speaker;
    int needed_bytes;
    int cmd;
    int use_hdma;
bellard authored
81
82
    int highspeed;
    int can_write;
83
84
85

    int v2x6;
bellard authored
86
87
88
89
90
91
92
93
94
    uint8_t csp_param;
    uint8_t csp_value;
    uint8_t csp_mode;
    uint8_t csp_regs[256];
    uint8_t csp_index;
    uint8_t csp_reg83[4];
    int csp_reg83r;
    int csp_reg83w;
95
    uint8_t in2_data[10];
bellard authored
96
97
98
99
    uint8_t out_data[50];
    uint8_t test_reg;
    uint8_t last_read_byte;
    int nzero;
100
101
102

    int left_till_irq;
bellard authored
103
104
105
    int dma_running;
    int bytes_per_second;
    int align;
106
107
    int audio_free;
    SWVoiceOut *voice;
bellard authored
108
109
    QEMUTimer *aux_ts;
110
111
    /* mixer state */
    int mixer_nreg;
bellard authored
112
    uint8_t mixer_regs[256];
113
} SB16State;
114
115
116
static void SB_audio_callback (void *opaque, int free);
bellard authored
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
static int magic_of_irq (int irq)
{
    switch (irq) {
    case 5:
        return 2;
    case 7:
        return 4;
    case 9:
        return 1;
    case 10:
        return 8;
    default:
        dolog ("bad irq %d\n", irq);
        return 2;
    }
}

static int irq_of_magic (int magic)
{
    switch (magic) {
    case 1:
        return 9;
    case 2:
        return 5;
    case 4:
        return 7;
    case 8:
        return 10;
    default:
        dolog ("bad irq magic %d\n", magic);
        return -1;
    }
}

#if 0
152
153
static void log_dsp (SB16State *dsp)
{
bellard authored
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
    ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
            dsp->fmt_stereo ? "Stereo" : "Mono",
            dsp->fmt_signed ? "Signed" : "Unsigned",
            dsp->fmt_bits,
            dsp->dma_auto ? "Auto" : "Single",
            dsp->block_size,
            dsp->freq,
            dsp->time_const,
            dsp->speaker);
}
#endif

static void speaker (SB16State *s, int on)
{
    s->speaker = on;
    /* AUD_enable (s->voice, on); */
170
171
}
bellard authored
172
static void control (SB16State *s, int hold)
173
{
bellard authored
174
175
176
177
178
    int dma = s->use_hdma ? s->hdma : s->dma;
    s->dma_running = hold;

    ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma);
179
    if (hold) {
bellard authored
180
        DMA_hold_DREQ (dma);
181
        AUD_set_active_out (s->voice, 1);
182
183
    }
    else {
bellard authored
184
        DMA_release_DREQ (dma);
185
        AUD_set_active_out (s->voice, 0);
186
187
188
    }
}
bellard authored
189
static void aux_timer (void *opaque)
190
{
bellard authored
191
192
    SB16State *s = opaque;
    s->can_write = 1;
pbrook authored
193
    qemu_irq_raise (s->pic[s->irq]);
bellard authored
194
195
196
197
198
}

#define DMA8_AUTO 1
#define DMA8_HIGH 2
199
200
201
static void continue_dma8 (SB16State *s)
{
    if (s->freq > 0) {
malc authored
202
        struct audsettings as;
203
204
205
206
207
208

        s->audio_free = 0;

        as.freq = s->freq;
        as.nchannels = 1 << s->fmt_stereo;
        as.fmt = s->fmt;
209
        as.endianness = 0;
210
211
212
213
214
215
216

        s->voice = AUD_open_out (
            &s->card,
            s->voice,
            "sb16",
            s,
            SB_audio_callback,
217
            &as
218
219
220
221
222
223
            );
    }

    control (s, 1);
}
bellard authored
224
225
226
227
228
229
230
231
static void dma_cmd8 (SB16State *s, int mask, int dma_len)
{
    s->fmt = AUD_FMT_U8;
    s->use_hdma = 0;
    s->fmt_bits = 8;
    s->fmt_signed = 0;
    s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
    if (-1 == s->time_const) {
232
233
        if (s->freq <= 0)
            s->freq = 11025;
bellard authored
234
235
236
237
238
239
    }
    else {
        int tmp = (256 - s->time_const);
        s->freq = (1000000 + (tmp / 2)) / tmp;
    }
240
    if (dma_len != -1) {
bellard authored
241
        s->block_size = dma_len << s->fmt_stereo;
242
    }
bellard authored
243
244
245
246
247
248
249
250
251
252
    else {
        /* This is apparently the only way to make both Act1/PL
           and SecondReality/FC work

           Act1 sets block size via command 0x48 and it's an odd number
           SR does the same with even number
           Both use stereo, and Creatives own documentation states that
           0x48 sets block size in bytes less one.. go figure */
        s->block_size &= ~s->fmt_stereo;
    }
bellard authored
253
254
255
256
257
258
259
260

    s->freq >>= s->fmt_stereo;
    s->left_till_irq = s->block_size;
    s->bytes_per_second = (s->freq << s->fmt_stereo);
    /* s->highspeed = (mask & DMA8_HIGH) != 0; */
    s->dma_auto = (mask & DMA8_AUTO) != 0;
    s->align = (1 << s->fmt_stereo) - 1;
261
262
263
264
    if (s->block_size & s->align) {
        dolog ("warning: misaligned block size %d, alignment %d\n",
               s->block_size, s->align + 1);
    }
bellard authored
265
bellard authored
266
267
268
269
270
    ldebug ("freq %d, stereo %d, sign %d, bits %d, "
            "dma %d, auto %d, fifo %d, high %d\n",
            s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
            s->block_size, s->dma_auto, s->fifo, s->highspeed);
271
    continue_dma8 (s);
bellard authored
272
273
    speaker (s, 1);
}
274
bellard authored
275
276
277
278
279
280
281
static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
{
    s->use_hdma = cmd < 0xc0;
    s->fifo = (cmd >> 1) & 1;
    s->dma_auto = (cmd >> 2) & 1;
    s->fmt_signed = (d0 >> 4) & 1;
    s->fmt_stereo = (d0 >> 5) & 1;
282
283
284

    switch (cmd >> 4) {
    case 11:
bellard authored
285
        s->fmt_bits = 16;
286
287
288
        break;

    case 12:
bellard authored
289
        s->fmt_bits = 8;
290
291
292
        break;
    }
bellard authored
293
294
295
296
297
298
299
300
301
    if (-1 != s->time_const) {
#if 1
        int tmp = 256 - s->time_const;
        s->freq = (1000000 + (tmp / 2)) / tmp;
#else
        /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */
        s->freq = 1000000 / ((255 - s->time_const));
#endif
        s->time_const = -1;
302
303
    }
bellard authored
304
305
    s->block_size = dma_len + 1;
    s->block_size <<= (s->fmt_bits == 16);
bellard authored
306
307
308
309
310
    if (!s->dma_auto) {
        /* It is clear that for DOOM and auto-init this value
           shouldn't take stereo into account, while Miles Sound Systems
           setsound.exe with single transfer mode wouldn't work without it
           wonders of SB16 yet again */
bellard authored
311
        s->block_size <<= s->fmt_stereo;
bellard authored
312
    }
313
bellard authored
314
315
316
317
    ldebug ("freq %d, stereo %d, sign %d, bits %d, "
            "dma %d, auto %d, fifo %d, high %d\n",
            s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
            s->block_size, s->dma_auto, s->fifo, s->highspeed);
318
bellard authored
319
320
321
    if (16 == s->fmt_bits) {
        if (s->fmt_signed) {
            s->fmt = AUD_FMT_S16;
322
323
        }
        else {
bellard authored
324
            s->fmt = AUD_FMT_U16;
325
326
327
        }
    }
    else {
bellard authored
328
329
        if (s->fmt_signed) {
            s->fmt = AUD_FMT_S8;
330
331
        }
        else {
bellard authored
332
            s->fmt = AUD_FMT_U8;
333
334
335
        }
    }
bellard authored
336
    s->left_till_irq = s->block_size;
337
bellard authored
338
339
340
    s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16);
    s->highspeed = 0;
    s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1;
341
342
343
344
    if (s->block_size & s->align) {
        dolog ("warning: misaligned block size %d, alignment %d\n",
               s->block_size, s->align + 1);
    }
345
346
    if (s->freq) {
malc authored
347
        struct audsettings as;
bellard authored
348
349
        s->audio_free = 0;
bellard authored
350
351
352
353

        as.freq = s->freq;
        as.nchannels = 1 << s->fmt_stereo;
        as.fmt = s->fmt;
354
        as.endianness = 0;
bellard authored
355
356
        s->voice = AUD_open_out (
bellard authored
357
            &s->card,
358
359
360
361
            s->voice,
            "sb16",
            s,
            SB_audio_callback,
362
            &as
363
364
            );
    }
365
bellard authored
366
367
    control (s, 1);
    speaker (s, 1);
368
369
}
bellard authored
370
static inline void dsp_out_data (SB16State *s, uint8_t val)
bellard authored
371
{
bellard authored
372
    ldebug ("outdata %#x\n", val);
bellard authored
373
    if ((size_t) s->out_data_len < sizeof (s->out_data)) {
bellard authored
374
        s->out_data[s->out_data_len++] = val;
375
    }
bellard authored
376
377
}
bellard authored
378
static inline uint8_t dsp_get_data (SB16State *s)
379
{
380
    if (s->in_index) {
bellard authored
381
        return s->in2_data[--s->in_index];
382
    }
bellard authored
383
384
    else {
        dolog ("buffer underflow\n");
385
        return 0;
bellard authored
386
    }
387
388
}
bellard authored
389
static void command (SB16State *s, uint8_t cmd)
390
{
bellard authored
391
    ldebug ("command %#x\n", cmd);
392
393

    if (cmd > 0xaf && cmd < 0xd0) {
bellard authored
394
395
396
        if (cmd & 8) {
            dolog ("ADC not yet supported (command %#x)\n", cmd);
        }
397
398
399
400
401
402

        switch (cmd >> 4) {
        case 11:
        case 12:
            break;
        default:
bellard authored
403
            dolog ("%#x wrong bits\n", cmd);
404
        }
bellard authored
405
        s->needed_bytes = 3;
406
407
    }
    else {
408
409
        s->needed_bytes = 0;
410
        switch (cmd) {
411
        case 0x03:
bellard authored
412
413
414
            dsp_out_data (s, 0x10); /* s->csp_param); */
            goto warn;
bellard authored
415
        case 0x04:
bellard authored
416
417
            s->needed_bytes = 1;
            goto warn;
bellard authored
418
419

        case 0x05:
bellard authored
420
421
422
423
424
425
            s->needed_bytes = 2;
            goto warn;

        case 0x08:
            /* __asm__ ("int3"); */
            goto warn;
426
bellard authored
427
        case 0x0e:
bellard authored
428
429
430
431
432
433
            s->needed_bytes = 2;
            goto warn;

        case 0x09:
            dsp_out_data (s, 0xf8);
            goto warn;
bellard authored
434
435

        case 0x0f:
bellard authored
436
437
            s->needed_bytes = 1;
            goto warn;
bellard authored
438
439
        case 0x10:
bellard authored
440
441
            s->needed_bytes = 1;
            goto warn;
442
443

        case 0x14:
bellard authored
444
445
            s->needed_bytes = 2;
            s->block_size = 0;
446
447
            break;
bellard authored
448
        case 0x1c:              /* Auto-Initialize DMA DAC, 8-bit */
449
            dma_cmd8 (s, DMA8_AUTO, -1);
bellard authored
450
451
            break;
bellard authored
452
453
454
        case 0x20:              /* Direct ADC, Juice/PL */
            dsp_out_data (s, 0xff);
            goto warn;
455
456

        case 0x35:
457
            dolog ("0x35 - MIDI command not implemented\n");
458
459
460
            break;

        case 0x40:
bellard authored
461
462
463
            s->freq = -1;
            s->time_const = -1;
            s->needed_bytes = 1;
464
465
466
            break;

        case 0x41:
bellard authored
467
468
469
            s->freq = -1;
            s->time_const = -1;
            s->needed_bytes = 2;
470
471
            break;
bellard authored
472
473
474
475
476
477
        case 0x42:
            s->freq = -1;
            s->time_const = -1;
            s->needed_bytes = 2;
            goto warn;
478
        case 0x45:
bellard authored
479
480
481
            dsp_out_data (s, 0xaa);
            goto warn;
482
483
484
485
        case 0x47:                /* Continue Auto-Initialize DMA 16bit */
            break;

        case 0x48:
bellard authored
486
            s->needed_bytes = 2;
487
488
            break;
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
        case 0x74:
            s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
            dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n");
            break;

        case 0x75:              /* DMA DAC, 4-bit ADPCM Reference */
            s->needed_bytes = 2;
            dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n");
            break;

        case 0x76:              /* DMA DAC, 2.6-bit ADPCM */
            s->needed_bytes = 2;
            dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n");
            break;

        case 0x77:              /* DMA DAC, 2.6-bit ADPCM Reference */
            s->needed_bytes = 2;
            dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n");
            break;

        case 0x7d:
            dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n");
            dolog ("not implemented\n");
            break;

        case 0x7f:
            dolog (
                "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"
                );
            dolog ("not implemented\n");
            break;
521
        case 0x80:
bellard authored
522
            s->needed_bytes = 2;
523
524
525
526
            break;

        case 0x90:
        case 0x91:
bellard authored
527
528
            dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1);
            break;
529
bellard authored
530
531
532
        case 0xd0:              /* halt DMA operation. 8bit */
            control (s, 0);
            break;
533
bellard authored
534
535
        case 0xd1:              /* speaker on */
            speaker (s, 1);
536
537
            break;
bellard authored
538
539
540
        case 0xd3:              /* speaker off */
            speaker (s, 0);
            break;
541
bellard authored
542
        case 0xd4:              /* continue DMA operation. 8bit */
543
544
545
            /* KQ6 (or maybe Sierras audblst.drv in general) resets
               the frequency between halt/continue */
            continue_dma8 (s);
546
547
            break;
bellard authored
548
549
        case 0xd5:              /* halt DMA operation. 16bit */
            control (s, 0);
550
551
            break;
bellard authored
552
553
        case 0xd6:              /* continue DMA operation. 16bit */
            control (s, 1);
554
555
            break;
bellard authored
556
557
558
        case 0xd9:              /* exit auto-init DMA after this block. 16bit */
            s->dma_auto = 0;
            break;
559
bellard authored
560
561
        case 0xda:              /* exit auto-init DMA after this block. 8bit */
            s->dma_auto = 0;
562
563
            break;
564
        case 0xe0:              /* DSP identification */
bellard authored
565
            s->needed_bytes = 1;
566
            break;
567
568

        case 0xe1:
bellard authored
569
570
571
572
573
574
575
            dsp_out_data (s, s->ver & 0xff);
            dsp_out_data (s, s->ver >> 8);
            break;

        case 0xe2:
            s->needed_bytes = 1;
            goto warn;
576
bellard authored
577
578
579
        case 0xe3:
            {
                int i;
bellard authored
580
581
                for (i = sizeof (e3) - 1; i >= 0; --i)
                    dsp_out_data (s, e3[i]);
bellard authored
582
            }
bellard authored
583
            break;
bellard authored
584
585
        case 0xe4:              /* write test reg */
bellard authored
586
            s->needed_bytes = 1;
587
588
            break;
bellard authored
589
590
        case 0xe7:
            dolog ("Attempt to probe for ESS (0xe7)?\n");
591
            break;
bellard authored
592
593
        case 0xe8:              /* read test reg */
bellard authored
594
            dsp_out_data (s, s->test_reg);
595
596
            break;
597
        case 0xf2:
bellard authored
598
599
600
        case 0xf3:
            dsp_out_data (s, 0xaa);
            s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
pbrook authored
601
            qemu_irq_raise (s->pic[s->irq]);
bellard authored
602
            break;
603
604
        case 0xf9:
bellard authored
605
606
            s->needed_bytes = 1;
            goto warn;
607
608

        case 0xfa:
bellard authored
609
610
            dsp_out_data (s, 0);
            goto warn;
611
612

        case 0xfc:              /* FIXME */
bellard authored
613
614
            dsp_out_data (s, 0);
            goto warn;
615
616
        default:
617
618
            dolog ("Unrecognized command %#x\n", cmd);
            break;
619
620
        }
    }
bellard authored
621
622
    if (!s->needed_bytes) {
bellard authored
623
        ldebug ("\n");
624
625
626
627
628
629
630
631
632
    }

 exit:
    if (!s->needed_bytes) {
        s->cmd = -1;
    }
    else {
        s->cmd = cmd;
    }
633
634
    return;
bellard authored
635
 warn:
bellard authored
636
    dolog ("warning: command %#x,%d is not truly understood yet\n",
bellard authored
637
           cmd, s->needed_bytes);
638
639
    goto exit;
640
641
}
bellard authored
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
static uint16_t dsp_get_lohi (SB16State *s)
{
    uint8_t hi = dsp_get_data (s);
    uint8_t lo = dsp_get_data (s);
    return (hi << 8) | lo;
}

static uint16_t dsp_get_hilo (SB16State *s)
{
    uint8_t lo = dsp_get_data (s);
    uint8_t hi = dsp_get_data (s);
    return (hi << 8) | lo;
}

static void complete (SB16State *s)
657
{
658
    int d0, d1, d2;
bellard authored
659
660
    ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
            s->cmd, s->in_index, s->needed_bytes);
661
bellard authored
662
663
664
665
    if (s->cmd > 0xaf && s->cmd < 0xd0) {
        d2 = dsp_get_data (s);
        d1 = dsp_get_data (s);
        d0 = dsp_get_data (s);
666
bellard authored
667
668
669
670
671
672
673
674
675
        if (s->cmd & 8) {
            dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
                   s->cmd, d0, d1, d2);
        }
        else {
            ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
                    s->cmd, d0, d1, d2);
            dma_cmd (s, s->cmd, d0, d1 + (d2 << 8));
        }
676
677
    }
    else {
bellard authored
678
        switch (s->cmd) {
bellard authored
679
        case 0x04:
bellard authored
680
681
682
683
            s->csp_mode = dsp_get_data (s);
            s->csp_reg83r = 0;
            s->csp_reg83w = 0;
            ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode);
684
685
            break;
bellard authored
686
687
688
689
690
691
        case 0x05:
            s->csp_param = dsp_get_data (s);
            s->csp_value = dsp_get_data (s);
            ldebug ("CSP command 0x05: param=%#x value=%#x\n",
                    s->csp_param,
                    s->csp_value);
bellard authored
692
            break;
693
694
        case 0x0e:
bellard authored
695
696
697
698
699
700
701
702
            d0 = dsp_get_data (s);
            d1 = dsp_get_data (s);
            ldebug ("write CSP register %d <- %#x\n", d1, d0);
            if (d1 == 0x83) {
                ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0);
                s->csp_reg83[s->csp_reg83r % 4] = d0;
                s->csp_reg83r += 1;
            }
703
            else {
bellard authored
704
                s->csp_regs[d1] = d0;
705
            }
706
707
            break;
bellard authored
708
709
710
711
712
713
714
715
716
717
718
        case 0x0f:
            d0 = dsp_get_data (s);
            ldebug ("read CSP register %#x -> %#x, mode=%#x\n",
                    d0, s->csp_regs[d0], s->csp_mode);
            if (d0 == 0x83) {
                ldebug ("0x83[%d] -> %#x\n",
                        s->csp_reg83w,
                        s->csp_reg83[s->csp_reg83w % 4]);
                dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]);
                s->csp_reg83w += 1;
            }
719
            else {
bellard authored
720
                dsp_out_data (s, s->csp_regs[d0]);
721
            }
bellard authored
722
            break;
723
bellard authored
724
725
726
727
        case 0x10:
            d0 = dsp_get_data (s);
            dolog ("cmd 0x10 d0=%#x\n", d0);
            break;
728
bellard authored
729
        case 0x14:
bellard authored
730
            dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
bellard authored
731
            break;
732
733

        case 0x40:
bellard authored
734
735
            s->time_const = dsp_get_data (s);
            ldebug ("set time const %d\n", s->time_const);
736
737
            break;
bellard authored
738
        case 0x42:              /* FT2 sets output freq with this, go figure */
739
#if 0
bellard authored
740
            dolog ("cmd 0x42 might not do what it think it should\n");
741
#endif
bellard authored
742
743
744
        case 0x41:
            s->freq = dsp_get_hilo (s);
            ldebug ("set freq %d\n", s->freq);
745
746
747
            break;

        case 0x48:
bellard authored
748
            s->block_size = dsp_get_lohi (s) + 1;
bellard authored
749
750
751
            ldebug ("set dma block len %d\n", s->block_size);
            break;
752
753
754
755
756
757
758
        case 0x74:
        case 0x75:
        case 0x76:
        case 0x77:
            /* ADPCM stuff, ignore */
            break;
bellard authored
759
760
        case 0x80:
            {
bellard authored
761
                int freq, samples, bytes;
bellard authored
762
763
                int64_t ticks;
bellard authored
764
765
                freq = s->freq > 0 ? s->freq : 11025;
                samples = dsp_get_lohi (s) + 1;
bellard authored
766
                bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
bellard authored
767
                ticks = (bytes * ticks_per_sec) / freq;
768
                if (ticks < ticks_per_sec / 1024) {
pbrook authored
769
                    qemu_irq_raise (s->pic[s->irq]);
770
771
772
773
774
775
776
777
778
                }
                else {
                    if (s->aux_ts) {
                        qemu_mod_timer (
                            s->aux_ts,
                            qemu_get_clock (vm_clock) + ticks
                            );
                    }
                }
bellard authored
779
                ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks);
bellard authored
780
            }
781
782
783
            break;

        case 0xe0:
bellard authored
784
785
786
            d0 = dsp_get_data (s);
            s->out_data_len = 0;
            ldebug ("E0 data = %#x\n", d0);
787
            dsp_out_data (s, ~d0);
788
789
            break;
bellard authored
790
791
        case 0xe2:
            d0 = dsp_get_data (s);
bellard authored
792
            ldebug ("E2 = %#x\n", d0);
793
794
            break;
bellard authored
795
796
797
        case 0xe4:
            s->test_reg = dsp_get_data (s);
            break;
798
799

        case 0xf9:
bellard authored
800
801
            d0 = dsp_get_data (s);
            ldebug ("command 0xf9 with %#x\n", d0);
802
            switch (d0) {
bellard authored
803
804
805
806
807
808
809
810
            case 0x0e:
                dsp_out_data (s, 0xff);
                break;

            case 0x0f:
                dsp_out_data (s, 0x07);
                break;
811
            case 0x37:
bellard authored
812
813
814
                dsp_out_data (s, 0x38);
                break;
815
            default:
bellard authored
816
817
                dsp_out_data (s, 0x00);
                break;
818
            }
819
820
821
            break;

        default:
bellard authored
822
            dolog ("complete: unrecognized command %#x\n", s->cmd);
823
            return;
824
825
826
        }
    }
bellard authored
827
828
    ldebug ("\n");
    s->cmd = -1;
829
830
831
    return;
}
832
833
static void legacy_reset (SB16State *s)
{
malc authored
834
    struct audsettings as;
835
836
837
838
839
840
841
842
843

    s->freq = 11025;
    s->fmt_signed = 0;
    s->fmt_bits = 8;
    s->fmt_stereo = 0;

    as.freq = s->freq;
    as.nchannels = 1;
    as.fmt = AUD_FMT_U8;
844
    as.endianness = 0;
845
846
847
848
849
850
851

    s->voice = AUD_open_out (
        &s->card,
        s->voice,
        "sb16",
        s,
        SB_audio_callback,
852
        &as
853
854
855
856
857
858
        );

    /* Not sure about that... */
    /* AUD_set_active_out (s->voice, 1); */
}
bellard authored
859
860
static void reset (SB16State *s)
{
pbrook authored
861
    qemu_irq_lower (s->pic[s->irq]);
bellard authored
862
    if (s->dma_auto) {
pbrook authored
863
864
        qemu_irq_raise (s->pic[s->irq]);
        qemu_irq_lower (s->pic[s->irq]);
bellard authored
865
866
867
868
869
870
871
872
873
874
875
876
    }

    s->mixer_regs[0x82] = 0;
    s->dma_auto = 0;
    s->in_index = 0;
    s->out_data_len = 0;
    s->left_till_irq = 0;
    s->needed_bytes = 0;
    s->block_size = -1;
    s->nzero = 0;
    s->highspeed = 0;
    s->v2x6 = 0;
877
    s->cmd = -1;
bellard authored
878
879
880
881

    dsp_out_data(s, 0xaa);
    speaker (s, 0);
    control (s, 0);
882
    legacy_reset (s);
bellard authored
883
884
}
885
886
static IO_WRITE_PROTO (dsp_write)
{
bellard authored
887
    SB16State *s = opaque;
888
889
    int iport;
bellard authored
890
    iport = nport - s->port;
891
bellard authored
892
    ldebug ("write %#x <- %#x\n", nport, val);
893
    switch (iport) {
bellard authored
894
895
896
897
898
899
    case 0x06:
        switch (val) {
        case 0x00:
            if (s->v2x6 == 1) {
                if (0 && s->highspeed) {
                    s->highspeed = 0;
pbrook authored
900
                    qemu_irq_lower (s->pic[s->irq]);
bellard authored
901
902
                    control (s, 0);
                }
903
                else {
bellard authored
904
                    reset (s);
905
                }
bellard authored
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
            }
            s->v2x6 = 0;
            break;

        case 0x01:
        case 0x03:              /* FreeBSD kludge */
            s->v2x6 = 1;
            break;

        case 0xc6:
            s->v2x6 = 0;        /* Prince of Persia, csp.sys, diagnose.exe */
            break;

        case 0xb8:              /* Panic */
            reset (s);
            break;

        case 0x39:
            dsp_out_data (s, 0x38);
            reset (s);
            s->v2x6 = 0x39;
            break;

        default:
            s->v2x6 = val;
            break;
932
933
934
        }
        break;
bellard authored
935
936
937
938
939
940
941
942
943
    case 0x0c:                  /* write data or command | write status */
/*         if (s->highspeed) */
/*             break; */

        if (0 == s->needed_bytes) {
            command (s, val);
#if 0
            if (0 == s->needed_bytes) {
                log_dsp (s);
944
            }
bellard authored
945
#endif
946
947
        }
        else {
bellard authored
948
            if (s->in_index == sizeof (s->in2_data)) {
949
950
951
                dolog ("in data overrun\n");
            }
            else {
bellard authored
952
953
954
955
956
957
958
959
                s->in2_data[s->in_index++] = val;
                if (s->in_index == s->needed_bytes) {
                    s->needed_bytes = 0;
                    complete (s);
#if 0
                    log_dsp (s);
#endif
                }
960
961
962
963
964
            }
        }
        break;

    default:
bellard authored
965
        ldebug ("(nport=%#x, val=%#x)\n", nport, val);
966
        break;
967
968
969
970
971
    }
}

static IO_READ_PROTO (dsp_read)
{
bellard authored
972
973
    SB16State *s = opaque;
    int iport, retval, ack = 0;
974
bellard authored
975
    iport = nport - s->port;
976
977

    switch (iport) {
bellard authored
978
979
    case 0x06:                  /* reset */
        retval = 0xff;
980
        break;
981
bellard authored
982
983
984
985
986
987
    case 0x0a:                  /* read data */
        if (s->out_data_len) {
            retval = s->out_data[--s->out_data_len];
            s->last_read_byte = retval;
        }
        else {
988
989
990
991
            if (s->cmd != -1) {
                dolog ("empty output buffer for command %#x\n",
                       s->cmd);
            }
bellard authored
992
            retval = s->last_read_byte;
993
            /* goto error; */
994
995
996
        }
        break;
bellard authored
997
998
    case 0x0c:                  /* 0 can write */
        retval = s->can_write ? 0 : 0x80;
999
1000
        break;
bellard authored
1001
1002
1003
1004
    case 0x0d:                  /* timer interrupt clear */
        /* dolog ("timer interrupt clear\n"); */
        retval = 0;
        break;
1005
bellard authored
1006
1007
1008
1009
1010
    case 0x0e:                  /* data available status | irq 8 ack */
        retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
        if (s->mixer_regs[0x82] & 1) {
            ack = 1;
            s->mixer_regs[0x82] &= 1;
pbrook authored
1011
            qemu_irq_lower (s->pic[s->irq]);
bellard authored
1012
        }
1013
1014
        break;
bellard authored
1015
    case 0x0f:                  /* irq 16 ack */
bellard authored
1016
        retval = 0xff;
bellard authored
1017
1018
1019
        if (s->mixer_regs[0x82] & 2) {
            ack = 1;
            s->mixer_regs[0x82] &= 2;
pbrook authored
1020
            qemu_irq_lower (s->pic[s->irq]);
bellard authored
1021
        }
1022
1023
1024
1025
1026
1027
        break;

    default:
        goto error;
    }
1028
    if (!ack) {
bellard authored
1029
        ldebug ("read %#x -> %#x\n", nport, retval);
1030
    }
1031
1032
1033
1034

    return retval;

 error:
1035
    dolog ("warning: dsp_read %#x error\n", nport);
1036
    return 0xff;
1037
1038
}
bellard authored
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
static void reset_mixer (SB16State *s)
{
    int i;

    memset (s->mixer_regs, 0xff, 0x7f);
    memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83);

    s->mixer_regs[0x02] = 4;    /* master volume 3bits */
    s->mixer_regs[0x06] = 4;    /* MIDI volume 3bits */
    s->mixer_regs[0x08] = 0;    /* CD volume 3bits */
    s->mixer_regs[0x0a] = 0;    /* voice volume 2bits */

    /* d5=input filt, d3=lowpass filt, d1,d2=input source */
    s->mixer_regs[0x0c] = 0;

    /* d5=output filt, d1=stereo switch */
    s->mixer_regs[0x0e] = 0;

    /* voice volume L d5,d7, R d1,d3 */
    s->mixer_regs[0x04] = (4 << 5) | (4 << 1);
    /* master ... */
    s->mixer_regs[0x22] = (4 << 5) | (4 << 1);
    /* MIDI ... */
    s->mixer_regs[0x26] = (4 << 5) | (4 << 1);

    for (i = 0x30; i < 0x48; i++) {
        s->mixer_regs[i] = 0x20;
    }
}
1069
1070
static IO_WRITE_PROTO(mixer_write_indexb)
{
bellard authored
1071
    SB16State *s = opaque;
bellard authored
1072
    (void) nport;
bellard authored
1073
    s->mixer_nreg = val;
1074
1075
1076
1077
}

static IO_WRITE_PROTO(mixer_write_datab)
{
bellard authored
1078
1079
    SB16State *s = opaque;
bellard authored
1080
    (void) nport;
bellard authored
1081
    ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
bellard authored
1082
bellard authored
1083
    switch (s->mixer_nreg) {
1084
    case 0x00:
bellard authored
1085
        reset_mixer (s);
1086
1087
1088
        break;

    case 0x80:
bellard authored
1089
1090
1091
        {
            int irq = irq_of_magic (val);
            ldebug ("setting irq to %d (val=%#x)\n", irq, val);
1092
            if (irq > 0) {
bellard authored
1093
                s->irq = irq;
1094
            }
bellard authored
1095
        }
1096
        break;
1097
bellard authored
1098
1099
1100
    case 0x81:
        {
            int dma, hdma;
1101
bellard authored
1102
1103
            dma = lsbindex (val & 0xf);
            hdma = lsbindex (val & 0xf0);
1104
1105
1106
1107
1108
1109
            if (dma != s->dma || hdma != s->hdma) {
                dolog (
                    "attempt to change DMA "
                    "8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
                    dma, s->dma, hdma, s->hdma, val);
            }
bellard authored
1110
1111
1112
1113
1114
1115
#if 0
            s->dma = dma;
            s->hdma = hdma;
#endif
        }
        break;
1116
bellard authored
1117
1118
1119
1120
    case 0x82:
        dolog ("attempt to write into IRQ status register (val=%#x)\n",
               val);
        return;
1121
bellard authored
1122
    default:
1123
1124
1125
        if (s->mixer_nreg >= 0x80) {
            ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
        }
bellard authored
1126
1127
1128
1129
        break;
    }

    s->mixer_regs[s->mixer_nreg] = val;
1130
1131
}
1132
1133
static IO_WRITE_PROTO(mixer_write_indexw)
{
bellard authored
1134
1135
    mixer_write_indexb (opaque, nport, val & 0xff);
    mixer_write_datab (opaque, nport, (val >> 8) & 0xff);
1136
1137
1138
1139
}

static IO_READ_PROTO(mixer_read)
{
bellard authored
1140
    SB16State *s = opaque;
bellard authored
1141
1142

    (void) nport;
bellard authored
1143
#ifndef DEBUG_SB16_MOST
1144
1145
1146
1147
1148
    if (s->mixer_nreg != 0x82) {
        ldebug ("mixer_read[%#x] -> %#x\n",
                s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
    }
#else
bellard authored
1149
1150
    ldebug ("mixer_read[%#x] -> %#x\n",
            s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
1151
#endif
bellard authored
1152
    return s->mixer_regs[s->mixer_nreg];
1153
1154
}
bellard authored
1155
1156
static int write_audio (SB16State *s, int nchan, int dma_pos,
                        int dma_len, int len)
1157
1158
{
    int temp, net;
1159
    uint8_t tmpbuf[4096];
1160
bellard authored
1161
    temp = len;
1162
1163
1164
    net = 0;

    while (temp) {
bellard authored
1165
        int left = dma_len - dma_pos;
bellard authored
1166
1167
        int copied;
        size_t to_copy;
1168
bellard authored
1169
        to_copy = audio_MIN (temp, left);
bellard authored
1170
1171
        if (to_copy > sizeof (tmpbuf)) {
            to_copy = sizeof (tmpbuf);
1172
        }
1173
bellard authored
1174
1175
        copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
        copied = AUD_write (s->voice, tmpbuf, copied);
1176
bellard authored
1177
1178
        temp -= copied;
        dma_pos = (dma_pos + copied) % dma_len;
1179
1180
        net += copied;
1181
        if (!copied) {
bellard authored
1182
            break;
1183
        }
1184
1185
1186
1187
1188
    }

    return net;
}
bellard authored
1189
static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
1190
{
bellard authored
1191
    SB16State *s = opaque;
1192
    int till, copy, written, free;
1193
1194
1195
1196
1197
1198
1199
    if (s->block_size <= 0) {
        dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
               s->block_size, nchan, dma_pos, dma_len);
        return dma_pos;
    }
bellard authored
1200
1201
    if (s->left_till_irq < 0) {
        s->left_till_irq = s->block_size;
1202
1203
    }
1204
1205
1206
1207
1208
1209
1210
1211
    if (s->voice) {
        free = s->audio_free & ~s->align;
        if ((free <= 0) || !dma_len) {
            return dma_pos;
        }
    }
    else {
        free = dma_len;
1212
1213
    }
bellard authored
1214
1215
    copy = free;
    till = s->left_till_irq;
1216
1217
#ifdef DEBUG_SB16_MOST
1218
1219
    dolog ("pos:%06d %d till:%d len:%d\n",
           dma_pos, free, till, dma_len);
1220
1221
#endif
1222
    if (till <= copy) {
bellard authored
1223
        if (0 == s->dma_auto) {
1224
1225
1226
1227
            copy = till;
        }
    }
bellard authored
1228
1229
1230
    written = write_audio (s, nchan, dma_pos, dma_len, copy);
    dma_pos = (dma_pos + written) % dma_len;
    s->left_till_irq -= written;
1231
bellard authored
1232
1233
    if (s->left_till_irq <= 0) {
        s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
pbrook authored
1234
        qemu_irq_raise (s->pic[s->irq]);
bellard authored
1235
1236
1237
        if (0 == s->dma_auto) {
            control (s, 0);
            speaker (s, 0);
1238
1239
1240
        }
    }
1241
#ifdef DEBUG_SB16_MOST
bellard authored
1242
1243
1244
    ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
            dma_pos, free, dma_len, s->left_till_irq, copy, written,
            s->block_size);
1245
#endif
1246
bellard authored
1247
1248
    while (s->left_till_irq <= 0) {
        s->left_till_irq = s->block_size + s->left_till_irq;
1249
1250
    }
bellard authored
1251
    return dma_pos;
1252
1253
}
1254
static void SB_audio_callback (void *opaque, int free)
1255
{
bellard authored
1256
    SB16State *s = opaque;
1257
    s->audio_free = free;
1258
1259
}
bellard authored
1260
static void SB_save (QEMUFile *f, void *opaque)
1261
{
bellard authored
1262
1263
    SB16State *s = opaque;
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
    qemu_put_be32 (f, s->irq);
    qemu_put_be32 (f, s->dma);
    qemu_put_be32 (f, s->hdma);
    qemu_put_be32 (f, s->port);
    qemu_put_be32 (f, s->ver);
    qemu_put_be32 (f, s->in_index);
    qemu_put_be32 (f, s->out_data_len);
    qemu_put_be32 (f, s->fmt_stereo);
    qemu_put_be32 (f, s->fmt_signed);
    qemu_put_be32 (f, s->fmt_bits);
bellard authored
1274
    qemu_put_be32s (f, &s->fmt);
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
    qemu_put_be32 (f, s->dma_auto);
    qemu_put_be32 (f, s->block_size);
    qemu_put_be32 (f, s->fifo);
    qemu_put_be32 (f, s->freq);
    qemu_put_be32 (f, s->time_const);
    qemu_put_be32 (f, s->speaker);
    qemu_put_be32 (f, s->needed_bytes);
    qemu_put_be32 (f, s->cmd);
    qemu_put_be32 (f, s->use_hdma);
    qemu_put_be32 (f, s->highspeed);
    qemu_put_be32 (f, s->can_write);
    qemu_put_be32 (f, s->v2x6);
bellard authored
1287
1288
1289
1290
1291
1292
1293
1294

    qemu_put_8s (f, &s->csp_param);
    qemu_put_8s (f, &s->csp_value);
    qemu_put_8s (f, &s->csp_mode);
    qemu_put_8s (f, &s->csp_param);
    qemu_put_buffer (f, s->csp_regs, 256);
    qemu_put_8s (f, &s->csp_index);
    qemu_put_buffer (f, s->csp_reg83, 4);
1295
1296
    qemu_put_be32 (f, s->csp_reg83r);
    qemu_put_be32 (f, s->csp_reg83w);
bellard authored
1297
1298
1299
1300
1301
1302

    qemu_put_buffer (f, s->in2_data, sizeof (s->in2_data));
    qemu_put_buffer (f, s->out_data, sizeof (s->out_data));
    qemu_put_8s (f, &s->test_reg);
    qemu_put_8s (f, &s->last_read_byte);
1303
1304
1305
1306
1307
    qemu_put_be32 (f, s->nzero);
    qemu_put_be32 (f, s->left_till_irq);
    qemu_put_be32 (f, s->dma_running);
    qemu_put_be32 (f, s->bytes_per_second);
    qemu_put_be32 (f, s->align);
bellard authored
1308
1309
    qemu_put_be32 (f, s->mixer_nreg);
bellard authored
1310
    qemu_put_buffer (f, s->mixer_regs, 256);
1311
1312
}
bellard authored
1313
static int SB_load (QEMUFile *f, void *opaque, int version_id)
1314
{
bellard authored
1315
1316
    SB16State *s = opaque;
1317
    if (version_id != 1) {
bellard authored
1318
        return -EINVAL;
1319
    }
bellard authored
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
    s->irq=qemu_get_be32 (f);
    s->dma=qemu_get_be32 (f);
    s->hdma=qemu_get_be32 (f);
    s->port=qemu_get_be32 (f);
    s->ver=qemu_get_be32 (f);
    s->in_index=qemu_get_be32 (f);
    s->out_data_len=qemu_get_be32 (f);
    s->fmt_stereo=qemu_get_be32 (f);
    s->fmt_signed=qemu_get_be32 (f);
    s->fmt_bits=qemu_get_be32 (f);
bellard authored
1331
    qemu_get_be32s (f, &s->fmt);
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
    s->dma_auto=qemu_get_be32 (f);
    s->block_size=qemu_get_be32 (f);
    s->fifo=qemu_get_be32 (f);
    s->freq=qemu_get_be32 (f);
    s->time_const=qemu_get_be32 (f);
    s->speaker=qemu_get_be32 (f);
    s->needed_bytes=qemu_get_be32 (f);
    s->cmd=qemu_get_be32 (f);
    s->use_hdma=qemu_get_be32 (f);
    s->highspeed=qemu_get_be32 (f);
    s->can_write=qemu_get_be32 (f);
    s->v2x6=qemu_get_be32 (f);
bellard authored
1344
1345
1346
1347
1348
1349
1350
1351

    qemu_get_8s (f, &s->csp_param);
    qemu_get_8s (f, &s->csp_value);
    qemu_get_8s (f, &s->csp_mode);
    qemu_get_8s (f, &s->csp_param);
    qemu_get_buffer (f, s->csp_regs, 256);
    qemu_get_8s (f, &s->csp_index);
    qemu_get_buffer (f, s->csp_reg83, 4);
1352
1353
    s->csp_reg83r=qemu_get_be32 (f);
    s->csp_reg83w=qemu_get_be32 (f);
bellard authored
1354
1355
1356
1357
1358
1359

    qemu_get_buffer (f, s->in2_data, sizeof (s->in2_data));
    qemu_get_buffer (f, s->out_data, sizeof (s->out_data));
    qemu_get_8s (f, &s->test_reg);
    qemu_get_8s (f, &s->last_read_byte);
1360
1361
1362
1363
1364
    s->nzero=qemu_get_be32 (f);
    s->left_till_irq=qemu_get_be32 (f);
    s->dma_running=qemu_get_be32 (f);
    s->bytes_per_second=qemu_get_be32 (f);
    s->align=qemu_get_be32 (f);
bellard authored
1365
1366
    s->mixer_nreg=qemu_get_be32 (f);
bellard authored
1367
1368
    qemu_get_buffer (f, s->mixer_regs, 256);
1369
    if (s->voice) {
bellard authored
1370
        AUD_close_out (&s->card, s->voice);
1371
1372
        s->voice = NULL;
    }
bellard authored
1373
1374

    if (s->dma_running) {
1375
        if (s->freq) {
malc authored
1376
            struct audsettings as;
bellard authored
1377
1378
            s->audio_free = 0;
bellard authored
1379
1380
1381
1382

            as.freq = s->freq;
            as.nchannels = 1 << s->fmt_stereo;
            as.fmt = s->fmt;
1383
            as.endianness = 0;
bellard authored
1384
1385
            s->voice = AUD_open_out (
bellard authored
1386
                &s->card,
1387
1388
1389
1390
                s->voice,
                "sb16",
                s,
                SB_audio_callback,
1391
                &as
1392
1393
                );
        }
bellard authored
1394
1395
1396

        control (s, 1);
        speaker (s, s->speaker);
1397
    }
bellard authored
1398
    return 0;
1399
1400
}
1401
int SB16_init (qemu_irq *pic)
1402
{
bellard authored
1403
    SB16State *s;
1404
1405
1406
1407
    int i;
    static const uint8_t dsp_write_ports[] = {0x6, 0xc};
    static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};
bellard authored
1408
1409
    s = qemu_mallocz (sizeof (*s));
1410
    s->cmd = -1;
pbrook authored
1411
    s->pic = pic;
bellard authored
1412
1413
1414
1415
1416
    s->irq = conf.irq;
    s->dma = conf.dma;
    s->hdma = conf.hdma;
    s->port = conf.port;
    s->ver = conf.ver_lo | (conf.ver_hi << 8);
bellard authored
1417
bellard authored
1418
1419
1420
1421
1422
1423
1424
1425
1426
    s->mixer_regs[0x80] = magic_of_irq (s->irq);
    s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
    s->mixer_regs[0x82] = 2 << 5;

    s->csp_regs[5] = 1;
    s->csp_regs[9] = 0xf8;

    reset_mixer (s);
    s->aux_ts = qemu_new_timer (vm_clock, aux_timer, s);
1427
    if (!s->aux_ts) {
bellard authored
1428
        dolog ("warning: Could not create auxiliary timer\n");
1429
    }
1430
1431
    for (i = 0; i < ARRAY_SIZE (dsp_write_ports); i++) {
bellard authored
1432
        register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s);
1433
1434
    }
1435
    for (i = 0; i < ARRAY_SIZE (dsp_read_ports); i++) {
bellard authored
1436
        register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s);
1437
1438
    }
bellard authored
1439
1440
1441
1442
    register_ioport_write (s->port + 0x4, 1, 1, mixer_write_indexb, s);
    register_ioport_write (s->port + 0x4, 1, 2, mixer_write_indexw, s);
    register_ioport_read (s->port + 0x5, 1, 1, mixer_read, s);
    register_ioport_write (s->port + 0x5, 1, 1, mixer_write_datab, s);
1443
bellard authored
1444
1445
1446
    DMA_register_channel (s->hdma, SB_read_DMA, s);
    DMA_register_channel (s->dma, SB_read_DMA, s);
    s->can_write = 1;
1447
bellard authored
1448
    register_savevm ("sb16", 0, 1, SB_save, SB_load, s);
1449
    AUD_register_card ("sb16", &s->card);
bellard authored
1450
    return 0;
1451
}