sb16.c 35.6 KB
Newer Older
B
bellard 已提交
1 2
/*
 * QEMU Soundblaster 16 emulation
3 4 5
 *
 * Copyright (c) 2003-2005 Vassili Karpov (malc)
 *
B
bellard 已提交
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.
 */
P
pbrook 已提交
24 25 26 27 28
#include "hw.h"
#include "audiodev.h"
#include "audio/audio.h"
#include "isa.h"
#include "qemu-timer.h"
B
bellard 已提交
29

B
bellard 已提交
30
#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
B
bellard 已提交
31 32 33 34

/* #define DEBUG */
/* #define DEBUG_SB16_MOST */

B
bellard 已提交
35 36 37 38 39 40
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif

B
bellard 已提交
41
#define IO_READ_PROTO(name)                             \
B
bellard 已提交
42
    uint32_t name (void *opaque, uint32_t nport)
B
bellard 已提交
43
#define IO_WRITE_PROTO(name)                                    \
B
bellard 已提交
44
    void name (void *opaque, uint32_t nport, uint32_t val)
B
bellard 已提交
45

B
bellard 已提交
46
static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
B
bellard 已提交
47

B
bellard 已提交
48 49 50 51 52 53 54
static struct {
    int ver_lo;
    int ver_hi;
    int irq;
    int dma;
    int hdma;
    int port;
B
bellard 已提交
55
} conf = {5, 4, 5, 1, 5, 0x220};
B
bellard 已提交
56

57
typedef struct SB16State {
B
bellard 已提交
58
    QEMUSoundCard card;
P
pbrook 已提交
59
    qemu_irq *pic;
B
bellard 已提交
60 61 62 63 64 65
    int irq;
    int dma;
    int hdma;
    int port;
    int ver;

B
bellard 已提交
66 67 68 69 70
    int in_index;
    int out_data_len;
    int fmt_stereo;
    int fmt_signed;
    int fmt_bits;
B
bellard 已提交
71
    audfmt_e fmt;
B
bellard 已提交
72
    int dma_auto;
B
bellard 已提交
73
    int block_size;
B
bellard 已提交
74 75 76 77 78 79 80
    int fifo;
    int freq;
    int time_const;
    int speaker;
    int needed_bytes;
    int cmd;
    int use_hdma;
B
bellard 已提交
81 82
    int highspeed;
    int can_write;
B
bellard 已提交
83 84 85

    int v2x6;

B
bellard 已提交
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;

B
bellard 已提交
95
    uint8_t in2_data[10];
B
bellard 已提交
96 97 98 99
    uint8_t out_data[50];
    uint8_t test_reg;
    uint8_t last_read_byte;
    int nzero;
B
bellard 已提交
100 101 102

    int left_till_irq;

B
bellard 已提交
103 104 105
    int dma_running;
    int bytes_per_second;
    int align;
106 107
    int audio_free;
    SWVoiceOut *voice;
B
bellard 已提交
108

109
    QEMUTimer *aux_ts;
110 111
    /* mixer state */
    int mixer_nreg;
B
bellard 已提交
112
    uint8_t mixer_regs[256];
113
} SB16State;
B
bellard 已提交
114

115 116
static void SB_audio_callback (void *opaque, int free);

B
bellard 已提交
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)
{
B
bellard 已提交
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); */
B
bellard 已提交
170 171
}

B
bellard 已提交
172
static void control (SB16State *s, int hold)
B
bellard 已提交
173
{
B
bellard 已提交
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);

B
bellard 已提交
179
    if (hold) {
B
bellard 已提交
180
        DMA_hold_DREQ (dma);
181
        AUD_set_active_out (s->voice, 1);
B
bellard 已提交
182 183
    }
    else {
B
bellard 已提交
184
        DMA_release_DREQ (dma);
185
        AUD_set_active_out (s->voice, 0);
B
bellard 已提交
186 187 188
    }
}

B
bellard 已提交
189
static void aux_timer (void *opaque)
B
bellard 已提交
190
{
B
bellard 已提交
191 192
    SB16State *s = opaque;
    s->can_write = 1;
P
pbrook 已提交
193
    qemu_irq_raise (s->pic[s->irq]);
B
bellard 已提交
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) {
M
malc 已提交
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;
B
bellard 已提交
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,
B
bellard 已提交
217
            &as
218 219 220 221 222 223
            );
    }

    control (s, 1);
}

B
bellard 已提交
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;
B
bellard 已提交
234 235 236 237 238 239
    }
    else {
        int tmp = (256 - s->time_const);
        s->freq = (1000000 + (tmp / 2)) / tmp;
    }

240
    if (dma_len != -1) {
B
bellard 已提交
241
        s->block_size = dma_len << s->fmt_stereo;
242
    }
B
bellard 已提交
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;
    }
B
bellard 已提交
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);
    }
B
bellard 已提交
265

B
bellard 已提交
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);
B
bellard 已提交
272 273
    speaker (s, 1);
}
B
bellard 已提交
274

B
bellard 已提交
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;
B
bellard 已提交
282 283 284

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

    case 12:
B
bellard 已提交
289
        s->fmt_bits = 8;
B
bellard 已提交
290 291 292
        break;
    }

B
bellard 已提交
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;
B
bellard 已提交
302 303
    }

B
bellard 已提交
304 305
    s->block_size = dma_len + 1;
    s->block_size <<= (s->fmt_bits == 16);
B
bellard 已提交
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 */
B
bellard 已提交
311
        s->block_size <<= s->fmt_stereo;
B
bellard 已提交
312
    }
B
bellard 已提交
313

B
bellard 已提交
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);
B
bellard 已提交
318

B
bellard 已提交
319 320 321
    if (16 == s->fmt_bits) {
        if (s->fmt_signed) {
            s->fmt = AUD_FMT_S16;
B
bellard 已提交
322 323
        }
        else {
B
bellard 已提交
324
            s->fmt = AUD_FMT_U16;
B
bellard 已提交
325 326 327
        }
    }
    else {
B
bellard 已提交
328 329
        if (s->fmt_signed) {
            s->fmt = AUD_FMT_S8;
B
bellard 已提交
330 331
        }
        else {
B
bellard 已提交
332
            s->fmt = AUD_FMT_U8;
B
bellard 已提交
333 334 335
        }
    }

B
bellard 已提交
336
    s->left_till_irq = s->block_size;
B
bellard 已提交
337

B
bellard 已提交
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);
    }
B
bellard 已提交
345

346
    if (s->freq) {
M
malc 已提交
347
        struct audsettings as;
B
bellard 已提交
348

349
        s->audio_free = 0;
B
bellard 已提交
350 351 352 353

        as.freq = s->freq;
        as.nchannels = 1 << s->fmt_stereo;
        as.fmt = s->fmt;
B
bellard 已提交
354
        as.endianness = 0;
B
bellard 已提交
355

356
        s->voice = AUD_open_out (
B
bellard 已提交
357
            &s->card,
358 359 360 361
            s->voice,
            "sb16",
            s,
            SB_audio_callback,
B
bellard 已提交
362
            &as
363 364
            );
    }
B
bellard 已提交
365

B
bellard 已提交
366 367
    control (s, 1);
    speaker (s, 1);
B
bellard 已提交
368 369
}

B
bellard 已提交
370
static inline void dsp_out_data (SB16State *s, uint8_t val)
B
bellard 已提交
371
{
B
bellard 已提交
372
    ldebug ("outdata %#x\n", val);
B
bellard 已提交
373
    if ((size_t) s->out_data_len < sizeof (s->out_data)) {
B
bellard 已提交
374
        s->out_data[s->out_data_len++] = val;
375
    }
B
bellard 已提交
376 377
}

B
bellard 已提交
378
static inline uint8_t dsp_get_data (SB16State *s)
B
bellard 已提交
379
{
380
    if (s->in_index) {
B
bellard 已提交
381
        return s->in2_data[--s->in_index];
382
    }
B
bellard 已提交
383 384
    else {
        dolog ("buffer underflow\n");
B
bellard 已提交
385
        return 0;
B
bellard 已提交
386
    }
B
bellard 已提交
387 388
}

B
bellard 已提交
389
static void command (SB16State *s, uint8_t cmd)
B
bellard 已提交
390
{
B
bellard 已提交
391
    ldebug ("command %#x\n", cmd);
B
bellard 已提交
392 393

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

        switch (cmd >> 4) {
        case 11:
        case 12:
            break;
        default:
B
bellard 已提交
403
            dolog ("%#x wrong bits\n", cmd);
B
bellard 已提交
404
        }
B
bellard 已提交
405
        s->needed_bytes = 3;
B
bellard 已提交
406 407
    }
    else {
408 409
        s->needed_bytes = 0;

B
bellard 已提交
410
        switch (cmd) {
B
bellard 已提交
411
        case 0x03:
B
bellard 已提交
412 413 414
            dsp_out_data (s, 0x10); /* s->csp_param); */
            goto warn;

B
bellard 已提交
415
        case 0x04:
B
bellard 已提交
416 417
            s->needed_bytes = 1;
            goto warn;
B
bellard 已提交
418 419

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

        case 0x08:
            /* __asm__ ("int3"); */
            goto warn;
B
bellard 已提交
426

B
bellard 已提交
427
        case 0x0e:
B
bellard 已提交
428 429 430 431 432 433
            s->needed_bytes = 2;
            goto warn;

        case 0x09:
            dsp_out_data (s, 0xf8);
            goto warn;
B
bellard 已提交
434 435

        case 0x0f:
B
bellard 已提交
436 437
            s->needed_bytes = 1;
            goto warn;
B
bellard 已提交
438

B
bellard 已提交
439
        case 0x10:
B
bellard 已提交
440 441
            s->needed_bytes = 1;
            goto warn;
B
bellard 已提交
442 443

        case 0x14:
B
bellard 已提交
444 445
            s->needed_bytes = 2;
            s->block_size = 0;
B
bellard 已提交
446 447
            break;

B
bellard 已提交
448
        case 0x1c:              /* Auto-Initialize DMA DAC, 8-bit */
449
            dma_cmd8 (s, DMA8_AUTO, -1);
B
bellard 已提交
450 451
            break;

B
bellard 已提交
452 453 454
        case 0x20:              /* Direct ADC, Juice/PL */
            dsp_out_data (s, 0xff);
            goto warn;
B
bellard 已提交
455 456

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

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

        case 0x41:
B
bellard 已提交
467 468 469
            s->freq = -1;
            s->time_const = -1;
            s->needed_bytes = 2;
B
bellard 已提交
470 471
            break;

B
bellard 已提交
472 473 474 475 476 477
        case 0x42:
            s->freq = -1;
            s->time_const = -1;
            s->needed_bytes = 2;
            goto warn;

B
bellard 已提交
478
        case 0x45:
B
bellard 已提交
479 480 481
            dsp_out_data (s, 0xaa);
            goto warn;

B
bellard 已提交
482 483 484 485
        case 0x47:                /* Continue Auto-Initialize DMA 16bit */
            break;

        case 0x48:
B
bellard 已提交
486
            s->needed_bytes = 2;
B
bellard 已提交
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;

B
bellard 已提交
521
        case 0x80:
B
bellard 已提交
522
            s->needed_bytes = 2;
B
bellard 已提交
523 524 525 526
            break;

        case 0x90:
        case 0x91:
B
bellard 已提交
527 528
            dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1);
            break;
B
bellard 已提交
529

B
bellard 已提交
530 531 532
        case 0xd0:              /* halt DMA operation. 8bit */
            control (s, 0);
            break;
B
bellard 已提交
533

B
bellard 已提交
534 535
        case 0xd1:              /* speaker on */
            speaker (s, 1);
B
bellard 已提交
536 537
            break;

B
bellard 已提交
538 539 540
        case 0xd3:              /* speaker off */
            speaker (s, 0);
            break;
B
bellard 已提交
541

B
bellard 已提交
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);
B
bellard 已提交
546 547
            break;

B
bellard 已提交
548 549
        case 0xd5:              /* halt DMA operation. 16bit */
            control (s, 0);
B
bellard 已提交
550 551
            break;

B
bellard 已提交
552 553
        case 0xd6:              /* continue DMA operation. 16bit */
            control (s, 1);
B
bellard 已提交
554 555
            break;

B
bellard 已提交
556 557 558
        case 0xd9:              /* exit auto-init DMA after this block. 16bit */
            s->dma_auto = 0;
            break;
B
bellard 已提交
559

B
bellard 已提交
560 561
        case 0xda:              /* exit auto-init DMA after this block. 8bit */
            s->dma_auto = 0;
B
bellard 已提交
562 563
            break;

564
        case 0xe0:              /* DSP identification */
B
bellard 已提交
565
            s->needed_bytes = 1;
566
            break;
B
bellard 已提交
567 568

        case 0xe1:
B
bellard 已提交
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;
B
bellard 已提交
576

B
bellard 已提交
577 578 579
        case 0xe3:
            {
                int i;
B
bellard 已提交
580 581
                for (i = sizeof (e3) - 1; i >= 0; --i)
                    dsp_out_data (s, e3[i]);
B
bellard 已提交
582
            }
B
bellard 已提交
583
            break;
B
bellard 已提交
584

B
bellard 已提交
585
        case 0xe4:              /* write test reg */
B
bellard 已提交
586
            s->needed_bytes = 1;
B
bellard 已提交
587 588
            break;

B
bellard 已提交
589 590
        case 0xe7:
            dolog ("Attempt to probe for ESS (0xe7)?\n");
591
            break;
B
bellard 已提交
592

B
bellard 已提交
593
        case 0xe8:              /* read test reg */
B
bellard 已提交
594
            dsp_out_data (s, s->test_reg);
B
bellard 已提交
595 596
            break;

B
bellard 已提交
597
        case 0xf2:
B
bellard 已提交
598 599 600
        case 0xf3:
            dsp_out_data (s, 0xaa);
            s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
P
pbrook 已提交
601
            qemu_irq_raise (s->pic[s->irq]);
B
bellard 已提交
602
            break;
B
bellard 已提交
603

B
bellard 已提交
604
        case 0xf9:
B
bellard 已提交
605 606
            s->needed_bytes = 1;
            goto warn;
B
bellard 已提交
607 608

        case 0xfa:
B
bellard 已提交
609 610
            dsp_out_data (s, 0);
            goto warn;
B
bellard 已提交
611 612

        case 0xfc:              /* FIXME */
B
bellard 已提交
613 614
            dsp_out_data (s, 0);
            goto warn;
B
bellard 已提交
615

B
bellard 已提交
616
        default:
617 618
            dolog ("Unrecognized command %#x\n", cmd);
            break;
B
bellard 已提交
619 620
        }
    }
B
bellard 已提交
621

622
    if (!s->needed_bytes) {
B
bellard 已提交
623
        ldebug ("\n");
624 625 626 627 628 629 630 631 632
    }

 exit:
    if (!s->needed_bytes) {
        s->cmd = -1;
    }
    else {
        s->cmd = cmd;
    }
B
bellard 已提交
633 634
    return;

B
bellard 已提交
635
 warn:
B
comment  
bellard 已提交
636
    dolog ("warning: command %#x,%d is not truly understood yet\n",
B
bellard 已提交
637
           cmd, s->needed_bytes);
638 639
    goto exit;

B
bellard 已提交
640 641
}

B
bellard 已提交
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)
B
bellard 已提交
657
{
B
bellard 已提交
658
    int d0, d1, d2;
B
bellard 已提交
659 660
    ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
            s->cmd, s->in_index, s->needed_bytes);
B
bellard 已提交
661

B
bellard 已提交
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);
B
bellard 已提交
666

B
bellard 已提交
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));
        }
B
bellard 已提交
676 677
    }
    else {
B
bellard 已提交
678
        switch (s->cmd) {
B
bellard 已提交
679
        case 0x04:
B
bellard 已提交
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);
B
bellard 已提交
684 685
            break;

B
bellard 已提交
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);
B
bellard 已提交
692
            break;
B
bellard 已提交
693

B
bellard 已提交
694
        case 0x0e:
B
bellard 已提交
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 {
B
bellard 已提交
704
                s->csp_regs[d1] = d0;
705
            }
B
bellard 已提交
706 707
            break;

B
bellard 已提交
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 {
B
bellard 已提交
720
                dsp_out_data (s, s->csp_regs[d0]);
721
            }
B
bellard 已提交
722
            break;
B
bellard 已提交
723

B
bellard 已提交
724 725 726 727
        case 0x10:
            d0 = dsp_get_data (s);
            dolog ("cmd 0x10 d0=%#x\n", d0);
            break;
B
bellard 已提交
728

B
bellard 已提交
729
        case 0x14:
B
bellard 已提交
730
            dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
B
bellard 已提交
731
            break;
B
bellard 已提交
732 733

        case 0x40:
B
bellard 已提交
734 735
            s->time_const = dsp_get_data (s);
            ldebug ("set time const %d\n", s->time_const);
B
bellard 已提交
736 737
            break;

B
bellard 已提交
738
        case 0x42:              /* FT2 sets output freq with this, go figure */
739
#if 0
B
bellard 已提交
740
            dolog ("cmd 0x42 might not do what it think it should\n");
741
#endif
B
bellard 已提交
742 743 744
        case 0x41:
            s->freq = dsp_get_hilo (s);
            ldebug ("set freq %d\n", s->freq);
B
bellard 已提交
745 746 747
            break;

        case 0x48:
B
bellard 已提交
748
            s->block_size = dsp_get_lohi (s) + 1;
B
bellard 已提交
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;

B
bellard 已提交
759 760
        case 0x80:
            {
B
bellard 已提交
761
                int freq, samples, bytes;
B
bellard 已提交
762 763
                int64_t ticks;

B
bellard 已提交
764 765
                freq = s->freq > 0 ? s->freq : 11025;
                samples = dsp_get_lohi (s) + 1;
B
bellard 已提交
766
                bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
B
bellard 已提交
767
                ticks = (bytes * ticks_per_sec) / freq;
768
                if (ticks < ticks_per_sec / 1024) {
P
pbrook 已提交
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
                            );
                    }
                }
B
bellard 已提交
779
                ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks);
B
bellard 已提交
780
            }
B
bellard 已提交
781 782 783
            break;

        case 0xe0:
B
bellard 已提交
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);
B
bellard 已提交
788 789
            break;

B
bellard 已提交
790 791
        case 0xe2:
            d0 = dsp_get_data (s);
B
bellard 已提交
792
            ldebug ("E2 = %#x\n", d0);
B
bellard 已提交
793 794
            break;

B
bellard 已提交
795 796 797
        case 0xe4:
            s->test_reg = dsp_get_data (s);
            break;
B
bellard 已提交
798 799

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

            case 0x0f:
                dsp_out_data (s, 0x07);
                break;

B
bellard 已提交
811
            case 0x37:
B
bellard 已提交
812 813 814
                dsp_out_data (s, 0x38);
                break;

B
bellard 已提交
815
            default:
B
bellard 已提交
816 817
                dsp_out_data (s, 0x00);
                break;
B
bellard 已提交
818
            }
B
bellard 已提交
819 820 821
            break;

        default:
B
bellard 已提交
822
            dolog ("complete: unrecognized command %#x\n", s->cmd);
823
            return;
B
bellard 已提交
824 825 826
        }
    }

B
bellard 已提交
827 828
    ldebug ("\n");
    s->cmd = -1;
B
bellard 已提交
829 830 831
    return;
}

832 833
static void legacy_reset (SB16State *s)
{
M
malc 已提交
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;
B
bellard 已提交
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,
B
bellard 已提交
852
        &as
853 854 855 856 857 858
        );

    /* Not sure about that... */
    /* AUD_set_active_out (s->voice, 1); */
}

B
bellard 已提交
859 860
static void reset (SB16State *s)
{
P
pbrook 已提交
861
    qemu_irq_lower (s->pic[s->irq]);
B
bellard 已提交
862
    if (s->dma_auto) {
P
pbrook 已提交
863 864
        qemu_irq_raise (s->pic[s->irq]);
        qemu_irq_lower (s->pic[s->irq]);
B
bellard 已提交
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;
B
bellard 已提交
878 879 880 881

    dsp_out_data(s, 0xaa);
    speaker (s, 0);
    control (s, 0);
882
    legacy_reset (s);
B
bellard 已提交
883 884
}

B
bellard 已提交
885 886
static IO_WRITE_PROTO (dsp_write)
{
B
bellard 已提交
887
    SB16State *s = opaque;
B
bellard 已提交
888 889
    int iport;

B
bellard 已提交
890
    iport = nport - s->port;
B
bellard 已提交
891

B
bellard 已提交
892
    ldebug ("write %#x <- %#x\n", nport, val);
B
bellard 已提交
893
    switch (iport) {
B
bellard 已提交
894 895 896 897 898 899
    case 0x06:
        switch (val) {
        case 0x00:
            if (s->v2x6 == 1) {
                if (0 && s->highspeed) {
                    s->highspeed = 0;
P
pbrook 已提交
900
                    qemu_irq_lower (s->pic[s->irq]);
B
bellard 已提交
901 902
                    control (s, 0);
                }
903
                else {
B
bellard 已提交
904
                    reset (s);
905
                }
B
bellard 已提交
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;
B
bellard 已提交
932 933 934
        }
        break;

B
bellard 已提交
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);
B
bellard 已提交
944
            }
B
bellard 已提交
945
#endif
B
bellard 已提交
946 947
        }
        else {
B
bellard 已提交
948
            if (s->in_index == sizeof (s->in2_data)) {
B
bellard 已提交
949 950 951
                dolog ("in data overrun\n");
            }
            else {
B
bellard 已提交
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
                }
B
bellard 已提交
960 961 962 963 964
            }
        }
        break;

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

static IO_READ_PROTO (dsp_read)
{
B
bellard 已提交
972 973
    SB16State *s = opaque;
    int iport, retval, ack = 0;
B
bellard 已提交
974

B
bellard 已提交
975
    iport = nport - s->port;
B
bellard 已提交
976 977

    switch (iport) {
B
bellard 已提交
978 979
    case 0x06:                  /* reset */
        retval = 0xff;
B
bellard 已提交
980
        break;
B
bellard 已提交
981

B
bellard 已提交
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);
            }
B
bellard 已提交
992
            retval = s->last_read_byte;
B
bellard 已提交
993
            /* goto error; */
B
bellard 已提交
994 995 996
        }
        break;

B
bellard 已提交
997 998
    case 0x0c:                  /* 0 can write */
        retval = s->can_write ? 0 : 0x80;
B
bellard 已提交
999 1000
        break;

B
bellard 已提交
1001 1002 1003 1004
    case 0x0d:                  /* timer interrupt clear */
        /* dolog ("timer interrupt clear\n"); */
        retval = 0;
        break;
B
bellard 已提交
1005

B
bellard 已提交
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;
P
pbrook 已提交
1011
            qemu_irq_lower (s->pic[s->irq]);
B
bellard 已提交
1012
        }
B
bellard 已提交
1013 1014
        break;

B
bellard 已提交
1015
    case 0x0f:                  /* irq 16 ack */
B
bellard 已提交
1016
        retval = 0xff;
B
bellard 已提交
1017 1018 1019
        if (s->mixer_regs[0x82] & 2) {
            ack = 1;
            s->mixer_regs[0x82] &= 2;
P
pbrook 已提交
1020
            qemu_irq_lower (s->pic[s->irq]);
B
bellard 已提交
1021
        }
B
bellard 已提交
1022 1023 1024 1025 1026 1027
        break;

    default:
        goto error;
    }

1028
    if (!ack) {
B
bellard 已提交
1029
        ldebug ("read %#x -> %#x\n", nport, retval);
1030
    }
B
bellard 已提交
1031 1032 1033 1034

    return retval;

 error:
1035
    dolog ("warning: dsp_read %#x error\n", nport);
B
bellard 已提交
1036
    return 0xff;
B
bellard 已提交
1037 1038
}

B
bellard 已提交
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
static IO_WRITE_PROTO (mixer_write_indexb)
B
bellard 已提交
1070
{
B
bellard 已提交
1071
    SB16State *s = opaque;
B
bellard 已提交
1072
    (void) nport;
B
bellard 已提交
1073
    s->mixer_nreg = val;
B
bellard 已提交
1074 1075
}

1076
static IO_WRITE_PROTO (mixer_write_datab)
B
bellard 已提交
1077
{
B
bellard 已提交
1078 1079
    SB16State *s = opaque;

B
bellard 已提交
1080
    (void) nport;
B
bellard 已提交
1081
    ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
B
bellard 已提交
1082

B
bellard 已提交
1083
    switch (s->mixer_nreg) {
B
bellard 已提交
1084
    case 0x00:
B
bellard 已提交
1085
        reset_mixer (s);
B
bellard 已提交
1086 1087 1088
        break;

    case 0x80:
B
bellard 已提交
1089 1090 1091
        {
            int irq = irq_of_magic (val);
            ldebug ("setting irq to %d (val=%#x)\n", irq, val);
1092
            if (irq > 0) {
B
bellard 已提交
1093
                s->irq = irq;
1094
            }
B
bellard 已提交
1095
        }
B
bellard 已提交
1096
        break;
B
bellard 已提交
1097

B
bellard 已提交
1098 1099 1100
    case 0x81:
        {
            int dma, hdma;
B
bellard 已提交
1101

B
bellard 已提交
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);
            }
B
bellard 已提交
1110 1111 1112 1113 1114 1115
#if 0
            s->dma = dma;
            s->hdma = hdma;
#endif
        }
        break;
B
bellard 已提交
1116

B
bellard 已提交
1117 1118 1119 1120
    case 0x82:
        dolog ("attempt to write into IRQ status register (val=%#x)\n",
               val);
        return;
B
bellard 已提交
1121

B
bellard 已提交
1122
    default:
1123 1124 1125
        if (s->mixer_nreg >= 0x80) {
            ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
        }
B
bellard 已提交
1126 1127 1128 1129
        break;
    }

    s->mixer_regs[s->mixer_nreg] = val;
B
bellard 已提交
1130 1131
}

1132
static IO_WRITE_PROTO (mixer_write_indexw)
B
bellard 已提交
1133
{
B
bellard 已提交
1134 1135
    mixer_write_indexb (opaque, nport, val & 0xff);
    mixer_write_datab (opaque, nport, (val >> 8) & 0xff);
B
bellard 已提交
1136 1137
}

1138
static IO_READ_PROTO (mixer_read)
B
bellard 已提交
1139
{
B
bellard 已提交
1140
    SB16State *s = opaque;
B
bellard 已提交
1141 1142

    (void) nport;
B
bellard 已提交
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
B
bellard 已提交
1149 1150
    ldebug ("mixer_read[%#x] -> %#x\n",
            s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
1151
#endif
B
bellard 已提交
1152
    return s->mixer_regs[s->mixer_nreg];
B
bellard 已提交
1153 1154
}

B
bellard 已提交
1155 1156
static int write_audio (SB16State *s, int nchan, int dma_pos,
                        int dma_len, int len)
B
bellard 已提交
1157 1158
{
    int temp, net;
1159
    uint8_t tmpbuf[4096];
B
bellard 已提交
1160

B
bellard 已提交
1161
    temp = len;
B
bellard 已提交
1162 1163 1164
    net = 0;

    while (temp) {
B
bellard 已提交
1165
        int left = dma_len - dma_pos;
B
bellard 已提交
1166 1167
        int copied;
        size_t to_copy;
B
bellard 已提交
1168

B
bellard 已提交
1169
        to_copy = audio_MIN (temp, left);
B
bellard 已提交
1170 1171
        if (to_copy > sizeof (tmpbuf)) {
            to_copy = sizeof (tmpbuf);
1172
        }
B
bellard 已提交
1173

B
bellard 已提交
1174 1175
        copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
        copied = AUD_write (s->voice, tmpbuf, copied);
B
bellard 已提交
1176

B
bellard 已提交
1177 1178
        temp -= copied;
        dma_pos = (dma_pos + copied) % dma_len;
B
bellard 已提交
1179 1180
        net += copied;

1181
        if (!copied) {
B
bellard 已提交
1182
            break;
1183
        }
B
bellard 已提交
1184 1185 1186 1187 1188
    }

    return net;
}

B
bellard 已提交
1189
static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
B
bellard 已提交
1190
{
B
bellard 已提交
1191
    SB16State *s = opaque;
1192
    int till, copy, written, free;
B
bellard 已提交
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;
    }

B
bellard 已提交
1200 1201
    if (s->left_till_irq < 0) {
        s->left_till_irq = s->block_size;
B
bellard 已提交
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;
B
bellard 已提交
1212 1213
    }

B
bellard 已提交
1214 1215
    copy = free;
    till = s->left_till_irq;
B
bellard 已提交
1216

B
bellard 已提交
1217
#ifdef DEBUG_SB16_MOST
1218 1219
    dolog ("pos:%06d %d till:%d len:%d\n",
           dma_pos, free, till, dma_len);
B
bellard 已提交
1220 1221
#endif

B
bellard 已提交
1222
    if (till <= copy) {
B
bellard 已提交
1223
        if (0 == s->dma_auto) {
B
bellard 已提交
1224 1225 1226 1227
            copy = till;
        }
    }

B
bellard 已提交
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;
B
bellard 已提交
1231

B
bellard 已提交
1232 1233
    if (s->left_till_irq <= 0) {
        s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
P
pbrook 已提交
1234
        qemu_irq_raise (s->pic[s->irq]);
B
bellard 已提交
1235 1236 1237
        if (0 == s->dma_auto) {
            control (s, 0);
            speaker (s, 0);
B
bellard 已提交
1238 1239 1240
        }
    }

B
bellard 已提交
1241
#ifdef DEBUG_SB16_MOST
B
bellard 已提交
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);
B
bellard 已提交
1245
#endif
B
bellard 已提交
1246

B
bellard 已提交
1247 1248
    while (s->left_till_irq <= 0) {
        s->left_till_irq = s->block_size + s->left_till_irq;
B
bellard 已提交
1249 1250
    }

B
bellard 已提交
1251
    return dma_pos;
B
bellard 已提交
1252 1253
}

1254
static void SB_audio_callback (void *opaque, int free)
B
bellard 已提交
1255
{
B
bellard 已提交
1256
    SB16State *s = opaque;
1257
    s->audio_free = free;
B
bellard 已提交
1258 1259
}

B
bellard 已提交
1260
static void SB_save (QEMUFile *f, void *opaque)
B
bellard 已提交
1261
{
B
bellard 已提交
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);
B
bellard 已提交
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);
B
bellard 已提交
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);
B
bellard 已提交
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);
B
bellard 已提交
1308

1309
    qemu_put_be32 (f, s->mixer_nreg);
B
bellard 已提交
1310
    qemu_put_buffer (f, s->mixer_regs, 256);
B
bellard 已提交
1311 1312
}

B
bellard 已提交
1313
static int SB_load (QEMUFile *f, void *opaque, int version_id)
B
bellard 已提交
1314
{
B
bellard 已提交
1315 1316
    SB16State *s = opaque;

1317
    if (version_id != 1) {
B
bellard 已提交
1318
        return -EINVAL;
1319
    }
B
bellard 已提交
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);
B
bellard 已提交
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);
B
bellard 已提交
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);
B
bellard 已提交
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);
B
bellard 已提交
1365

1366
    s->mixer_nreg=qemu_get_be32 (f);
B
bellard 已提交
1367 1368
    qemu_get_buffer (f, s->mixer_regs, 256);

B
bellard 已提交
1369
    if (s->voice) {
B
bellard 已提交
1370
        AUD_close_out (&s->card, s->voice);
B
bellard 已提交
1371 1372
        s->voice = NULL;
    }
B
bellard 已提交
1373 1374

    if (s->dma_running) {
1375
        if (s->freq) {
M
malc 已提交
1376
            struct audsettings as;
B
bellard 已提交
1377

1378
            s->audio_free = 0;
B
bellard 已提交
1379 1380 1381 1382

            as.freq = s->freq;
            as.nchannels = 1 << s->fmt_stereo;
            as.fmt = s->fmt;
B
bellard 已提交
1383
            as.endianness = 0;
B
bellard 已提交
1384

1385
            s->voice = AUD_open_out (
B
bellard 已提交
1386
                &s->card,
1387 1388 1389 1390
                s->voice,
                "sb16",
                s,
                SB_audio_callback,
B
bellard 已提交
1391
                &as
1392 1393
                );
        }
B
bellard 已提交
1394 1395 1396

        control (s, 1);
        speaker (s, s->speaker);
B
bellard 已提交
1397
    }
B
bellard 已提交
1398
    return 0;
B
bellard 已提交
1399 1400
}

P
Paul Brook 已提交
1401
int SB16_init (qemu_irq *pic)
B
bellard 已提交
1402
{
B
bellard 已提交
1403
    SB16State *s;
B
bellard 已提交
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};

B
bellard 已提交
1408 1409
    s = qemu_mallocz (sizeof (*s));

1410
    s->cmd = -1;
P
pbrook 已提交
1411
    s->pic = pic;
B
bellard 已提交
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);
B
bellard 已提交
1417

B
bellard 已提交
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) {
B
bellard 已提交
1428
        dolog ("warning: Could not create auxiliary timer\n");
1429
    }
B
bellard 已提交
1430

1431
    for (i = 0; i < ARRAY_SIZE (dsp_write_ports); i++) {
B
bellard 已提交
1432
        register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s);
B
bellard 已提交
1433 1434
    }

1435
    for (i = 0; i < ARRAY_SIZE (dsp_read_ports); i++) {
B
bellard 已提交
1436
        register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s);
B
bellard 已提交
1437 1438
    }

B
bellard 已提交
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);
B
bellard 已提交
1443

B
bellard 已提交
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;
B
bellard 已提交
1447

B
bellard 已提交
1448
    register_savevm ("sb16", 0, 1, SB_save, SB_load, s);
1449
    AUD_register_card ("sb16", &s->card);
B
bellard 已提交
1450
    return 0;
B
bellard 已提交
1451
}