Blame view

hw/sb16.c 35.8 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
bellard authored
30
#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
31
32
#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
bellard authored
33
34
35
36

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

    int v2x6;
bellard authored
88
89
90
91
92
93
94
95
96
    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;
97
    uint8_t in2_data[10];
bellard authored
98
99
100
101
    uint8_t out_data[50];
    uint8_t test_reg;
    uint8_t last_read_byte;
    int nzero;
102
103
104

    int left_till_irq;
bellard authored
105
106
107
    int dma_running;
    int bytes_per_second;
    int align;
108
109
    int audio_free;
    SWVoiceOut *voice;
bellard authored
110
111
    QEMUTimer *aux_ts;
112
113
    /* mixer state */
    int mixer_nreg;
bellard authored
114
    uint8_t mixer_regs[256];
115
} SB16State;
116
117
118
static void SB_audio_callback (void *opaque, int free);
bellard authored
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
152
153
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
154
155
static void log_dsp (SB16State *dsp)
{
bellard authored
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
    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); */
172
173
}
bellard authored
174
static void control (SB16State *s, int hold)
175
{
bellard authored
176
177
178
179
180
    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);
181
    if (hold) {
bellard authored
182
        DMA_hold_DREQ (dma);
183
        AUD_set_active_out (s->voice, 1);
184
185
    }
    else {
bellard authored
186
        DMA_release_DREQ (dma);
187
        AUD_set_active_out (s->voice, 0);
188
189
190
    }
}
bellard authored
191
static void aux_timer (void *opaque)
192
{
bellard authored
193
194
    SB16State *s = opaque;
    s->can_write = 1;
pbrook authored
195
    qemu_irq_raise (s->pic[s->irq]);
bellard authored
196
197
198
199
200
}

#define DMA8_AUTO 1
#define DMA8_HIGH 2
201
202
203
204
205
206
207
208
209
210
static void continue_dma8 (SB16State *s)
{
    if (s->freq > 0) {
        audsettings_t as;

        s->audio_free = 0;

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

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

    control (s, 1);
}
bellard authored
226
227
228
229
230
231
232
233
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) {
234
235
        if (s->freq <= 0)
            s->freq = 11025;
bellard authored
236
237
238
239
240
241
    }
    else {
        int tmp = (256 - s->time_const);
        s->freq = (1000000 + (tmp / 2)) / tmp;
    }
242
    if (dma_len != -1) {
bellard authored
243
        s->block_size = dma_len << s->fmt_stereo;
244
    }
bellard authored
245
246
247
248
249
250
251
252
253
254
    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
255
256
257
258
259
260
261
262

    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;
263
264
265
266
    if (s->block_size & s->align) {
        dolog ("warning: misaligned block size %d, alignment %d\n",
               s->block_size, s->align + 1);
    }
bellard authored
267
bellard authored
268
269
270
271
272
    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);
273
    continue_dma8 (s);
bellard authored
274
275
    speaker (s, 1);
}
276
bellard authored
277
278
279
280
281
282
283
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;
284
285
286

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

    case 12:
bellard authored
291
        s->fmt_bits = 8;
292
293
294
        break;
    }
bellard authored
295
296
297
298
299
300
301
302
303
    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;
304
305
    }
bellard authored
306
307
    s->block_size = dma_len + 1;
    s->block_size <<= (s->fmt_bits == 16);
bellard authored
308
309
310
311
312
    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
313
        s->block_size <<= s->fmt_stereo;
bellard authored
314
    }
315
bellard authored
316
317
318
319
    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);
320
bellard authored
321
322
323
    if (16 == s->fmt_bits) {
        if (s->fmt_signed) {
            s->fmt = AUD_FMT_S16;
324
325
        }
        else {
bellard authored
326
            s->fmt = AUD_FMT_U16;
327
328
329
        }
    }
    else {
bellard authored
330
331
        if (s->fmt_signed) {
            s->fmt = AUD_FMT_S8;
332
333
        }
        else {
bellard authored
334
            s->fmt = AUD_FMT_U8;
335
336
337
        }
    }
bellard authored
338
    s->left_till_irq = s->block_size;
339
bellard authored
340
341
342
    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;
343
344
345
346
    if (s->block_size & s->align) {
        dolog ("warning: misaligned block size %d, alignment %d\n",
               s->block_size, s->align + 1);
    }
347
348
    if (s->freq) {
bellard authored
349
350
        audsettings_t as;
351
        s->audio_free = 0;
bellard authored
352
353
354
355

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

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

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

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

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

        case 0x09:
            dsp_out_data (s, 0xf8);
            goto warn;
bellard authored
436
437

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

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

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

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

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

        case 0x48:
bellard authored
488
            s->needed_bytes = 2;
489
490
            break;
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
521
522
        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;
523
        case 0x80:
bellard authored
524
            s->needed_bytes = 2;
525
526
527
528
            break;

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

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

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

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

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

 exit:
    if (!s->needed_bytes) {
        s->cmd = -1;
    }
    else {
        s->cmd = cmd;
    }
635
636
    return;
bellard authored
637
 warn:
bellard authored
638
    dolog ("warning: command %#x,%d is not truly understood yet\n",
bellard authored
639
           cmd, s->needed_bytes);
640
641
    goto exit;
642
643
}
bellard authored
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
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)
659
{
660
    int d0, d1, d2;
bellard authored
661
662
    ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
            s->cmd, s->in_index, s->needed_bytes);
663
bellard authored
664
665
666
667
    if (s->cmd > 0xaf && s->cmd < 0xd0) {
        d2 = dsp_get_data (s);
        d1 = dsp_get_data (s);
        d0 = dsp_get_data (s);
668
bellard authored
669
670
671
672
673
674
675
676
677
        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));
        }
678
679
    }
    else {
bellard authored
680
        switch (s->cmd) {
bellard authored
681
        case 0x04:
bellard authored
682
683
684
685
            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);
686
687
            break;
bellard authored
688
689
690
691
692
693
        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
694
            break;
695
696
        case 0x0e:
bellard authored
697
698
699
700
701
702
703
704
            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;
            }
705
            else {
bellard authored
706
                s->csp_regs[d1] = d0;
707
            }
708
709
            break;
bellard authored
710
711
712
713
714
715
716
717
718
719
720
        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;
            }
721
            else {
bellard authored
722
                dsp_out_data (s, s->csp_regs[d0]);
723
            }
bellard authored
724
            break;
725
bellard authored
726
727
728
729
        case 0x10:
            d0 = dsp_get_data (s);
            dolog ("cmd 0x10 d0=%#x\n", d0);
            break;
730
bellard authored
731
        case 0x14:
bellard authored
732
            dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
bellard authored
733
            break;
734
735

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

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

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

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

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

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

    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;
846
    as.endianness = 0;
847
848
849
850
851
852
853

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

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

    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;
879
    s->cmd = -1;
bellard authored
880
881
882
883

    dsp_out_data(s, 0xaa);
    speaker (s, 0);
    control (s, 0);
884
    legacy_reset (s);
bellard authored
885
886
}
887
888
static IO_WRITE_PROTO (dsp_write)
{
bellard authored
889
    SB16State *s = opaque;
890
891
    int iport;
bellard authored
892
    iport = nport - s->port;
893
bellard authored
894
    ldebug ("write %#x <- %#x\n", nport, val);
895
    switch (iport) {
bellard authored
896
897
898
899
900
901
    case 0x06:
        switch (val) {
        case 0x00:
            if (s->v2x6 == 1) {
                if (0 && s->highspeed) {
                    s->highspeed = 0;
pbrook authored
902
                    qemu_irq_lower (s->pic[s->irq]);
bellard authored
903
904
                    control (s, 0);
                }
905
                else {
bellard authored
906
                    reset (s);
907
                }
bellard authored
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
            }
            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;
934
935
936
        }
        break;
bellard authored
937
938
939
940
941
942
943
944
945
    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);
946
            }
bellard authored
947
#endif
948
949
        }
        else {
bellard authored
950
            if (s->in_index == sizeof (s->in2_data)) {
951
952
953
                dolog ("in data overrun\n");
            }
            else {
bellard authored
954
955
956
957
958
959
960
961
                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
                }
962
963
964
965
966
            }
        }
        break;

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

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

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

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

    return retval;

 error:
1037
    dolog ("warning: dsp_read %#x error\n", nport);
1038
    return 0xff;
1039
1040
}
bellard authored
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
1069
1070
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;
    }
}
1071
1072
static IO_WRITE_PROTO(mixer_write_indexb)
{
bellard authored
1073
    SB16State *s = opaque;
bellard authored
1074
    (void) nport;
bellard authored
1075
    s->mixer_nreg = val;
1076
1077
1078
1079
}

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

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

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

static IO_READ_PROTO(mixer_read)
{
bellard authored
1142
    SB16State *s = opaque;
bellard authored
1143
1144

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

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

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

    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);
1297
1298
    qemu_put_be32 (f, s->csp_reg83r);
    qemu_put_be32 (f, s->csp_reg83w);
bellard authored
1299
1300
1301
1302
1303
1304

    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);
1305
1306
1307
1308
1309
    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
1310
1311
    qemu_put_be32 (f, s->mixer_nreg);
bellard authored
1312
    qemu_put_buffer (f, s->mixer_regs, 256);
1313
1314
}
bellard authored
1315
static int SB_load (QEMUFile *f, void *opaque, int version_id)
1316
{
bellard authored
1317
1318
    SB16State *s = opaque;
1319
    if (version_id != 1) {
bellard authored
1320
        return -EINVAL;
1321
    }
bellard authored
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
    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
1333
    qemu_get_be32s (f, &s->fmt);
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
    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
1346
1347
1348
1349
1350
1351
1352
1353

    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);
1354
1355
    s->csp_reg83r=qemu_get_be32 (f);
    s->csp_reg83w=qemu_get_be32 (f);
bellard authored
1356
1357
1358
1359
1360
1361

    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);
1362
1363
1364
1365
1366
    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
1367
1368
    s->mixer_nreg=qemu_get_be32 (f);
bellard authored
1369
1370
    qemu_get_buffer (f, s->mixer_regs, 256);
1371
    if (s->voice) {
bellard authored
1372
        AUD_close_out (&s->card, s->voice);
1373
1374
        s->voice = NULL;
    }
bellard authored
1375
1376

    if (s->dma_running) {
1377
        if (s->freq) {
bellard authored
1378
1379
            audsettings_t as;
1380
            s->audio_free = 0;
bellard authored
1381
1382
1383
1384

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

        control (s, 1);
        speaker (s, s->speaker);
1399
    }
bellard authored
1400
    return 0;
1401
1402
}
pbrook authored
1403
int SB16_init (AudioState *audio, qemu_irq *pic)
1404
{
bellard authored
1405
    SB16State *s;
1406
1407
1408
1409
    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
1410
1411
1412
1413
1414
1415
1416
    if (!audio) {
        dolog ("No audio state\n");
        return -1;
    }

    s = qemu_mallocz (sizeof (*s));
    if (!s) {
bellard authored
1417
        dolog ("Could not allocate memory for SB16 (%zu bytes)\n",
bellard authored
1418
1419
1420
1421
               sizeof (*s));
        return -1;
    }
1422
    s->cmd = -1;
pbrook authored
1423
    s->pic = pic;
bellard authored
1424
1425
1426
1427
1428
    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
1429
bellard authored
1430
1431
1432
1433
1434
1435
1436
1437
1438
    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);
1439
    if (!s->aux_ts) {
bellard authored
1440
        dolog ("warning: Could not create auxiliary timer\n");
1441
    }
1442
1443

    for (i = 0; i < LENOFA (dsp_write_ports); i++) {
bellard authored
1444
        register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s);
1445
1446
1447
    }

    for (i = 0; i < LENOFA (dsp_read_ports); i++) {
bellard authored
1448
        register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s);
1449
1450
    }
bellard authored
1451
1452
1453
1454
    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);
1455
bellard authored
1456
1457
1458
    DMA_register_channel (s->hdma, SB_read_DMA, s);
    DMA_register_channel (s->dma, SB_read_DMA, s);
    s->can_write = 1;
1459
bellard authored
1460
    register_savevm ("sb16", 0, 1, SB_save, SB_load, s);
bellard authored
1461
1462
    AUD_register_card (audio, "sb16", &s->card);
    return 0;
1463
}