]> git.proxmox.com Git - mirror_qemu.git/blame - hw/audio/sb16.c
memory: make global_dirty_tracking a bitmask
[mirror_qemu.git] / hw / audio / sb16.c
CommitLineData
27503323
FB
1/*
2 * QEMU Soundblaster 16 emulation
1d14ffa9
FB
3 *
4 * Copyright (c) 2003-2005 Vassili Karpov (malc)
5 *
27503323
FB
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
0b8fa32f 24
6086a565 25#include "qemu/osdep.h"
8a824e4d 26#include "hw/audio/soundhw.h"
87ecb68b 27#include "audio/audio.h"
64552b6b 28#include "hw/irq.h"
0d09e41a 29#include "hw/isa/isa.h"
a27bd6c7 30#include "hw/qdev-properties.h"
d6454270 31#include "migration/vmstate.h"
1de7afc9
PB
32#include "qemu/timer.h"
33#include "qemu/host-utils.h"
8ec660b8 34#include "qemu/log.h"
0b8fa32f 35#include "qemu/module.h"
8ec660b8 36#include "qapi/error.h"
db1015e9 37#include "qom/object.h"
27503323 38
fb065187 39#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
15b61470
FB
40
41/* #define DEBUG */
42/* #define DEBUG_SB16_MOST */
43
fb065187
FB
44#ifdef DEBUG
45#define ldebug(...) dolog (__VA_ARGS__)
46#else
47#define ldebug(...)
48#endif
49
85571bc7 50static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
d329a6fb 51
399f05a6 52#define TYPE_SB16 "sb16"
8063396b 53OBJECT_DECLARE_SIMPLE_TYPE(SB16State, SB16)
399f05a6 54
db1015e9 55struct SB16State {
399f05a6
AF
56 ISADevice parent_obj;
57
c0fe3827 58 QEMUSoundCard card;
3a38d437 59 qemu_irq pic;
f7b4f61f
GH
60 uint32_t irq;
61 uint32_t dma;
62 uint32_t hdma;
63 uint32_t port;
64 uint32_t ver;
f203c16e
HP
65 IsaDma *isa_dma;
66 IsaDma *isa_hdma;
85571bc7 67
27503323
FB
68 int in_index;
69 int out_data_len;
70 int fmt_stereo;
71 int fmt_signed;
72 int fmt_bits;
85bc5852 73 AudioFormat fmt;
27503323 74 int dma_auto;
85571bc7 75 int block_size;
27503323
FB
76 int fifo;
77 int freq;
78 int time_const;
79 int speaker;
80 int needed_bytes;
81 int cmd;
27503323 82 int use_hdma;
85571bc7
FB
83 int highspeed;
84 int can_write;
27503323
FB
85
86 int v2x6;
87
85571bc7
FB
88 uint8_t csp_param;
89 uint8_t csp_value;
90 uint8_t csp_mode;
91 uint8_t csp_regs[256];
92 uint8_t csp_index;
93 uint8_t csp_reg83[4];
94 int csp_reg83r;
95 int csp_reg83w;
96
d75d9f6b 97 uint8_t in2_data[10];
85571bc7
FB
98 uint8_t out_data[50];
99 uint8_t test_reg;
100 uint8_t last_read_byte;
101 int nzero;
27503323
FB
102
103 int left_till_irq;
27503323 104
85571bc7
FB
105 int dma_running;
106 int bytes_per_second;
107 int align;
1d14ffa9
FB
108 int audio_free;
109 SWVoiceOut *voice;
85571bc7 110
1d14ffa9 111 QEMUTimer *aux_ts;
5e2a6443
FB
112 /* mixer state */
113 int mixer_nreg;
202a456a 114 uint8_t mixer_regs[256];
e305a165 115 PortioList portio_list;
db1015e9 116};
27503323 117
a2cd86a9
PMD
118#define SAMPLE_RATE_MIN 5000
119#define SAMPLE_RATE_MAX 45000
120
1d14ffa9
FB
121static void SB_audio_callback (void *opaque, int free);
122
85571bc7
FB
123static int magic_of_irq (int irq)
124{
125 switch (irq) {
126 case 5:
127 return 2;
128 case 7:
129 return 4;
130 case 9:
131 return 1;
132 case 10:
133 return 8;
134 default:
8ec660b8 135 qemu_log_mask(LOG_GUEST_ERROR, "bad irq %d\n", irq);
85571bc7
FB
136 return 2;
137 }
138}
139
140static int irq_of_magic (int magic)
141{
142 switch (magic) {
143 case 1:
144 return 9;
145 case 2:
146 return 5;
147 case 4:
148 return 7;
149 case 8:
150 return 10;
151 default:
8ec660b8 152 qemu_log_mask(LOG_GUEST_ERROR, "bad irq magic %d\n", magic);
85571bc7
FB
153 return -1;
154 }
155}
156
157#if 0
5e2a6443
FB
158static void log_dsp (SB16State *dsp)
159{
85571bc7
FB
160 ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
161 dsp->fmt_stereo ? "Stereo" : "Mono",
162 dsp->fmt_signed ? "Signed" : "Unsigned",
163 dsp->fmt_bits,
164 dsp->dma_auto ? "Auto" : "Single",
165 dsp->block_size,
166 dsp->freq,
167 dsp->time_const,
168 dsp->speaker);
169}
170#endif
171
172static void speaker (SB16State *s, int on)
173{
174 s->speaker = on;
175 /* AUD_enable (s->voice, on); */
27503323
FB
176}
177
85571bc7 178static void control (SB16State *s, int hold)
27503323 179{
85571bc7 180 int dma = s->use_hdma ? s->hdma : s->dma;
f203c16e
HP
181 IsaDma *isa_dma = s->use_hdma ? s->isa_hdma : s->isa_dma;
182 IsaDmaClass *k = ISADMA_GET_CLASS(isa_dma);
85571bc7
FB
183 s->dma_running = hold;
184
185 ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma);
186
27503323 187 if (hold) {
f203c16e 188 k->hold_DREQ(isa_dma, dma);
1d14ffa9 189 AUD_set_active_out (s->voice, 1);
27503323
FB
190 }
191 else {
f203c16e 192 k->release_DREQ(isa_dma, dma);
1d14ffa9 193 AUD_set_active_out (s->voice, 0);
27503323
FB
194 }
195}
196
85571bc7 197static void aux_timer (void *opaque)
27503323 198{
85571bc7
FB
199 SB16State *s = opaque;
200 s->can_write = 1;
3a38d437 201 qemu_irq_raise (s->pic);
85571bc7
FB
202}
203
204#define DMA8_AUTO 1
205#define DMA8_HIGH 2
206
feea13e1
FB
207static void continue_dma8 (SB16State *s)
208{
209 if (s->freq > 0) {
1ea879e5 210 struct audsettings as;
feea13e1
FB
211
212 s->audio_free = 0;
213
214 as.freq = s->freq;
215 as.nchannels = 1 << s->fmt_stereo;
216 as.fmt = s->fmt;
d929eba5 217 as.endianness = 0;
feea13e1
FB
218
219 s->voice = AUD_open_out (
220 &s->card,
221 s->voice,
222 "sb16",
223 s,
224 SB_audio_callback,
d929eba5 225 &as
feea13e1
FB
226 );
227 }
228
229 control (s, 1);
230}
231
60e543f5
QL
232static inline int restrict_sampling_rate(int freq)
233{
234 if (freq < SAMPLE_RATE_MIN) {
235 qemu_log_mask(LOG_GUEST_ERROR,
236 "sampling range too low: %d, increasing to %u\n",
237 freq, SAMPLE_RATE_MIN);
238 return SAMPLE_RATE_MIN;
239 } else if (freq > SAMPLE_RATE_MAX) {
240 qemu_log_mask(LOG_GUEST_ERROR,
241 "sampling range too high: %d, decreasing to %u\n",
242 freq, SAMPLE_RATE_MAX);
243 return SAMPLE_RATE_MAX;
244 } else {
245 return freq;
246 }
247}
248
85571bc7
FB
249static void dma_cmd8 (SB16State *s, int mask, int dma_len)
250{
85bc5852 251 s->fmt = AUDIO_FORMAT_U8;
85571bc7
FB
252 s->use_hdma = 0;
253 s->fmt_bits = 8;
254 s->fmt_signed = 0;
255 s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
256 if (-1 == s->time_const) {
feea13e1
FB
257 if (s->freq <= 0)
258 s->freq = 11025;
85571bc7
FB
259 }
260 else {
261 int tmp = (256 - s->time_const);
262 s->freq = (1000000 + (tmp / 2)) / tmp;
263 }
60e543f5 264 s->freq = restrict_sampling_rate(s->freq);
85571bc7 265
1d14ffa9 266 if (dma_len != -1) {
15b61470 267 s->block_size = dma_len << s->fmt_stereo;
1d14ffa9 268 }
15b61470
FB
269 else {
270 /* This is apparently the only way to make both Act1/PL
271 and SecondReality/FC work
272
273 Act1 sets block size via command 0x48 and it's an odd number
274 SR does the same with even number
275 Both use stereo, and Creatives own documentation states that
276 0x48 sets block size in bytes less one.. go figure */
277 s->block_size &= ~s->fmt_stereo;
278 }
85571bc7
FB
279
280 s->freq >>= s->fmt_stereo;
281 s->left_till_irq = s->block_size;
282 s->bytes_per_second = (s->freq << s->fmt_stereo);
283 /* s->highspeed = (mask & DMA8_HIGH) != 0; */
284 s->dma_auto = (mask & DMA8_AUTO) != 0;
285 s->align = (1 << s->fmt_stereo) - 1;
286
1d14ffa9 287 if (s->block_size & s->align) {
8ec660b8
JA
288 qemu_log_mask(LOG_GUEST_ERROR, "warning: misaligned block size %d,"
289 " alignment %d\n", s->block_size, s->align + 1);
1d14ffa9 290 }
15b61470 291
85571bc7
FB
292 ldebug ("freq %d, stereo %d, sign %d, bits %d, "
293 "dma %d, auto %d, fifo %d, high %d\n",
294 s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
295 s->block_size, s->dma_auto, s->fifo, s->highspeed);
296
feea13e1 297 continue_dma8 (s);
85571bc7
FB
298 speaker (s, 1);
299}
27503323 300
85571bc7
FB
301static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
302{
303 s->use_hdma = cmd < 0xc0;
304 s->fifo = (cmd >> 1) & 1;
305 s->dma_auto = (cmd >> 2) & 1;
306 s->fmt_signed = (d0 >> 4) & 1;
307 s->fmt_stereo = (d0 >> 5) & 1;
27503323
FB
308
309 switch (cmd >> 4) {
310 case 11:
85571bc7 311 s->fmt_bits = 16;
27503323
FB
312 break;
313
314 case 12:
85571bc7 315 s->fmt_bits = 8;
27503323
FB
316 break;
317 }
318
85571bc7
FB
319 if (-1 != s->time_const) {
320#if 1
321 int tmp = 256 - s->time_const;
322 s->freq = (1000000 + (tmp / 2)) / tmp;
323#else
324 /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */
325 s->freq = 1000000 / ((255 - s->time_const));
326#endif
327 s->time_const = -1;
27503323 328 }
27503323 329
85571bc7
FB
330 s->block_size = dma_len + 1;
331 s->block_size <<= (s->fmt_bits == 16);
15b61470
FB
332 if (!s->dma_auto) {
333 /* It is clear that for DOOM and auto-init this value
334 shouldn't take stereo into account, while Miles Sound Systems
335 setsound.exe with single transfer mode wouldn't work without it
336 wonders of SB16 yet again */
85571bc7 337 s->block_size <<= s->fmt_stereo;
15b61470 338 }
27503323 339
85571bc7
FB
340 ldebug ("freq %d, stereo %d, sign %d, bits %d, "
341 "dma %d, auto %d, fifo %d, high %d\n",
342 s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
343 s->block_size, s->dma_auto, s->fifo, s->highspeed);
27503323 344
85571bc7
FB
345 if (16 == s->fmt_bits) {
346 if (s->fmt_signed) {
85bc5852 347 s->fmt = AUDIO_FORMAT_S16;
27503323
FB
348 }
349 else {
85bc5852 350 s->fmt = AUDIO_FORMAT_U16;
27503323
FB
351 }
352 }
353 else {
85571bc7 354 if (s->fmt_signed) {
85bc5852 355 s->fmt = AUDIO_FORMAT_S8;
27503323
FB
356 }
357 else {
85bc5852 358 s->fmt = AUDIO_FORMAT_U8;
27503323
FB
359 }
360 }
361
85571bc7 362 s->left_till_irq = s->block_size;
27503323 363
85571bc7
FB
364 s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16);
365 s->highspeed = 0;
366 s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1;
1d14ffa9 367 if (s->block_size & s->align) {
8ec660b8
JA
368 qemu_log_mask(LOG_GUEST_ERROR, "warning: misaligned block size %d,"
369 " alignment %d\n", s->block_size, s->align + 1);
1d14ffa9 370 }
27503323 371
1d14ffa9 372 if (s->freq) {
1ea879e5 373 struct audsettings as;
c0fe3827 374
1d14ffa9 375 s->audio_free = 0;
c0fe3827
FB
376
377 as.freq = s->freq;
378 as.nchannels = 1 << s->fmt_stereo;
379 as.fmt = s->fmt;
d929eba5 380 as.endianness = 0;
c0fe3827 381
1d14ffa9 382 s->voice = AUD_open_out (
c0fe3827 383 &s->card,
1d14ffa9
FB
384 s->voice,
385 "sb16",
386 s,
387 SB_audio_callback,
d929eba5 388 &as
1d14ffa9
FB
389 );
390 }
27503323 391
85571bc7
FB
392 control (s, 1);
393 speaker (s, 1);
27503323
FB
394}
395
85571bc7 396static inline void dsp_out_data (SB16State *s, uint8_t val)
202a456a 397{
85571bc7 398 ldebug ("outdata %#x\n", val);
c0fe3827 399 if ((size_t) s->out_data_len < sizeof (s->out_data)) {
85571bc7 400 s->out_data[s->out_data_len++] = val;
1d14ffa9 401 }
202a456a
FB
402}
403
85571bc7 404static inline uint8_t dsp_get_data (SB16State *s)
d75d9f6b 405{
1d14ffa9 406 if (s->in_index) {
85571bc7 407 return s->in2_data[--s->in_index];
1d14ffa9 408 }
85571bc7
FB
409 else {
410 dolog ("buffer underflow\n");
d75d9f6b 411 return 0;
85571bc7 412 }
d75d9f6b
FB
413}
414
85571bc7 415static void command (SB16State *s, uint8_t cmd)
27503323 416{
85571bc7 417 ldebug ("command %#x\n", cmd);
27503323
FB
418
419 if (cmd > 0xaf && cmd < 0xd0) {
85571bc7 420 if (cmd & 8) {
8ec660b8
JA
421 qemu_log_mask(LOG_UNIMP, "ADC not yet supported (command %#x)\n",
422 cmd);
85571bc7 423 }
27503323
FB
424
425 switch (cmd >> 4) {
426 case 11:
427 case 12:
428 break;
429 default:
8ec660b8 430 qemu_log_mask(LOG_GUEST_ERROR, "%#x wrong bits\n", cmd);
27503323 431 }
85571bc7 432 s->needed_bytes = 3;
27503323
FB
433 }
434 else {
1d14ffa9
FB
435 s->needed_bytes = 0;
436
27503323 437 switch (cmd) {
d75d9f6b 438 case 0x03:
85571bc7
FB
439 dsp_out_data (s, 0x10); /* s->csp_param); */
440 goto warn;
441
d329a6fb 442 case 0x04:
85571bc7
FB
443 s->needed_bytes = 1;
444 goto warn;
d329a6fb
FB
445
446 case 0x05:
85571bc7
FB
447 s->needed_bytes = 2;
448 goto warn;
449
450 case 0x08:
451 /* __asm__ ("int3"); */
452 goto warn;
d75d9f6b 453
d329a6fb 454 case 0x0e:
85571bc7
FB
455 s->needed_bytes = 2;
456 goto warn;
457
458 case 0x09:
459 dsp_out_data (s, 0xf8);
460 goto warn;
d329a6fb
FB
461
462 case 0x0f:
85571bc7
FB
463 s->needed_bytes = 1;
464 goto warn;
d329a6fb 465
27503323 466 case 0x10:
85571bc7
FB
467 s->needed_bytes = 1;
468 goto warn;
27503323
FB
469
470 case 0x14:
85571bc7
FB
471 s->needed_bytes = 2;
472 s->block_size = 0;
27503323
FB
473 break;
474
15b61470 475 case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */
feea13e1 476 dma_cmd8 (s, DMA8_AUTO, -1);
15b61470
FB
477 break;
478
85571bc7
FB
479 case 0x20: /* Direct ADC, Juice/PL */
480 dsp_out_data (s, 0xff);
481 goto warn;
27503323
FB
482
483 case 0x35:
8ec660b8 484 qemu_log_mask(LOG_UNIMP, "0x35 - MIDI command not implemented\n");
27503323
FB
485 break;
486
487 case 0x40:
85571bc7
FB
488 s->freq = -1;
489 s->time_const = -1;
490 s->needed_bytes = 1;
27503323
FB
491 break;
492
493 case 0x41:
85571bc7
FB
494 s->freq = -1;
495 s->time_const = -1;
496 s->needed_bytes = 2;
27503323
FB
497 break;
498
85571bc7
FB
499 case 0x42:
500 s->freq = -1;
501 s->time_const = -1;
502 s->needed_bytes = 2;
503 goto warn;
504
d75d9f6b 505 case 0x45:
85571bc7
FB
506 dsp_out_data (s, 0xaa);
507 goto warn;
508
27503323
FB
509 case 0x47: /* Continue Auto-Initialize DMA 16bit */
510 break;
511
512 case 0x48:
85571bc7 513 s->needed_bytes = 2;
27503323
FB
514 break;
515
1d14ffa9
FB
516 case 0x74:
517 s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
8ec660b8
JA
518 qemu_log_mask(LOG_UNIMP, "0x75 - DMA DAC, 4-bit ADPCM not"
519 " implemented\n");
1d14ffa9
FB
520 break;
521
522 case 0x75: /* DMA DAC, 4-bit ADPCM Reference */
523 s->needed_bytes = 2;
8ec660b8
JA
524 qemu_log_mask(LOG_UNIMP, "0x74 - DMA DAC, 4-bit ADPCM Reference not"
525 " implemented\n");
1d14ffa9
FB
526 break;
527
528 case 0x76: /* DMA DAC, 2.6-bit ADPCM */
529 s->needed_bytes = 2;
8ec660b8
JA
530 qemu_log_mask(LOG_UNIMP, "0x74 - DMA DAC, 2.6-bit ADPCM not"
531 " implemented\n");
1d14ffa9
FB
532 break;
533
534 case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */
535 s->needed_bytes = 2;
8ec660b8
JA
536 qemu_log_mask(LOG_UNIMP, "0x74 - DMA DAC, 2.6-bit ADPCM Reference"
537 " not implemented\n");
1d14ffa9
FB
538 break;
539
540 case 0x7d:
8ec660b8
JA
541 qemu_log_mask(LOG_UNIMP, "0x7d - Autio-Initialize DMA DAC, 4-bit"
542 " ADPCM Reference\n");
543 qemu_log_mask(LOG_UNIMP, "not implemented\n");
1d14ffa9
FB
544 break;
545
546 case 0x7f:
8ec660b8
JA
547 qemu_log_mask(LOG_UNIMP, "0x7d - Autio-Initialize DMA DAC, 2.6-bit"
548 " ADPCM Reference\n");
549 qemu_log_mask(LOG_UNIMP, "not implemented\n");
1d14ffa9
FB
550 break;
551
27503323 552 case 0x80:
85571bc7 553 s->needed_bytes = 2;
27503323
FB
554 break;
555
556 case 0x90:
557 case 0x91:
85571bc7
FB
558 dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1);
559 break;
27503323 560
85571bc7
FB
561 case 0xd0: /* halt DMA operation. 8bit */
562 control (s, 0);
563 break;
27503323 564
85571bc7
FB
565 case 0xd1: /* speaker on */
566 speaker (s, 1);
27503323
FB
567 break;
568
85571bc7
FB
569 case 0xd3: /* speaker off */
570 speaker (s, 0);
571 break;
27503323 572
85571bc7 573 case 0xd4: /* continue DMA operation. 8bit */
feea13e1
FB
574 /* KQ6 (or maybe Sierras audblst.drv in general) resets
575 the frequency between halt/continue */
576 continue_dma8 (s);
27503323
FB
577 break;
578
85571bc7
FB
579 case 0xd5: /* halt DMA operation. 16bit */
580 control (s, 0);
27503323
FB
581 break;
582
85571bc7
FB
583 case 0xd6: /* continue DMA operation. 16bit */
584 control (s, 1);
27503323
FB
585 break;
586
85571bc7
FB
587 case 0xd9: /* exit auto-init DMA after this block. 16bit */
588 s->dma_auto = 0;
589 break;
27503323 590
85571bc7
FB
591 case 0xda: /* exit auto-init DMA after this block. 8bit */
592 s->dma_auto = 0;
27503323
FB
593 break;
594
1d14ffa9 595 case 0xe0: /* DSP identification */
85571bc7 596 s->needed_bytes = 1;
1d14ffa9 597 break;
27503323
FB
598
599 case 0xe1:
85571bc7
FB
600 dsp_out_data (s, s->ver & 0xff);
601 dsp_out_data (s, s->ver >> 8);
602 break;
603
604 case 0xe2:
605 s->needed_bytes = 1;
606 goto warn;
27503323 607
d329a6fb
FB
608 case 0xe3:
609 {
610 int i;
85571bc7
FB
611 for (i = sizeof (e3) - 1; i >= 0; --i)
612 dsp_out_data (s, e3[i]);
d329a6fb 613 }
85571bc7 614 break;
d329a6fb 615
d75d9f6b 616 case 0xe4: /* write test reg */
85571bc7 617 s->needed_bytes = 1;
d75d9f6b
FB
618 break;
619
85571bc7 620 case 0xe7:
8ec660b8 621 qemu_log_mask(LOG_UNIMP, "Attempt to probe for ESS (0xe7)?\n");
1d14ffa9 622 break;
85571bc7 623
d75d9f6b 624 case 0xe8: /* read test reg */
85571bc7 625 dsp_out_data (s, s->test_reg);
d75d9f6b
FB
626 break;
627
27503323 628 case 0xf2:
85571bc7
FB
629 case 0xf3:
630 dsp_out_data (s, 0xaa);
631 s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
3a38d437 632 qemu_irq_raise (s->pic);
85571bc7 633 break;
27503323 634
d75d9f6b 635 case 0xf9:
85571bc7
FB
636 s->needed_bytes = 1;
637 goto warn;
d75d9f6b
FB
638
639 case 0xfa:
85571bc7
FB
640 dsp_out_data (s, 0);
641 goto warn;
d75d9f6b
FB
642
643 case 0xfc: /* FIXME */
85571bc7
FB
644 dsp_out_data (s, 0);
645 goto warn;
d75d9f6b 646
27503323 647 default:
8ec660b8 648 qemu_log_mask(LOG_UNIMP, "Unrecognized command %#x\n", cmd);
1d14ffa9 649 break;
27503323
FB
650 }
651 }
85571bc7 652
1d14ffa9 653 if (!s->needed_bytes) {
85571bc7 654 ldebug ("\n");
1d14ffa9
FB
655 }
656
657 exit:
658 if (!s->needed_bytes) {
659 s->cmd = -1;
660 }
661 else {
662 s->cmd = cmd;
663 }
27503323
FB
664 return;
665
85571bc7 666 warn:
8ec660b8
JA
667 qemu_log_mask(LOG_UNIMP, "warning: command %#x,%d is not truly understood"
668 " yet\n", cmd, s->needed_bytes);
1d14ffa9
FB
669 goto exit;
670
27503323
FB
671}
672
85571bc7
FB
673static uint16_t dsp_get_lohi (SB16State *s)
674{
675 uint8_t hi = dsp_get_data (s);
676 uint8_t lo = dsp_get_data (s);
677 return (hi << 8) | lo;
678}
679
680static uint16_t dsp_get_hilo (SB16State *s)
681{
682 uint8_t lo = dsp_get_data (s);
683 uint8_t hi = dsp_get_data (s);
684 return (hi << 8) | lo;
685}
686
687static void complete (SB16State *s)
27503323 688{
d75d9f6b 689 int d0, d1, d2;
85571bc7
FB
690 ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
691 s->cmd, s->in_index, s->needed_bytes);
27503323 692
85571bc7
FB
693 if (s->cmd > 0xaf && s->cmd < 0xd0) {
694 d2 = dsp_get_data (s);
695 d1 = dsp_get_data (s);
696 d0 = dsp_get_data (s);
27503323 697
85571bc7
FB
698 if (s->cmd & 8) {
699 dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
700 s->cmd, d0, d1, d2);
701 }
702 else {
703 ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
704 s->cmd, d0, d1, d2);
705 dma_cmd (s, s->cmd, d0, d1 + (d2 << 8));
706 }
27503323
FB
707 }
708 else {
85571bc7 709 switch (s->cmd) {
d329a6fb 710 case 0x04:
85571bc7
FB
711 s->csp_mode = dsp_get_data (s);
712 s->csp_reg83r = 0;
713 s->csp_reg83w = 0;
714 ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode);
d75d9f6b
FB
715 break;
716
85571bc7
FB
717 case 0x05:
718 s->csp_param = dsp_get_data (s);
719 s->csp_value = dsp_get_data (s);
720 ldebug ("CSP command 0x05: param=%#x value=%#x\n",
721 s->csp_param,
722 s->csp_value);
d329a6fb 723 break;
27503323 724
d75d9f6b 725 case 0x0e:
85571bc7
FB
726 d0 = dsp_get_data (s);
727 d1 = dsp_get_data (s);
728 ldebug ("write CSP register %d <- %#x\n", d1, d0);
729 if (d1 == 0x83) {
730 ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0);
731 s->csp_reg83[s->csp_reg83r % 4] = d0;
732 s->csp_reg83r += 1;
733 }
1d14ffa9 734 else {
85571bc7 735 s->csp_regs[d1] = d0;
1d14ffa9 736 }
27503323
FB
737 break;
738
85571bc7
FB
739 case 0x0f:
740 d0 = dsp_get_data (s);
741 ldebug ("read CSP register %#x -> %#x, mode=%#x\n",
742 d0, s->csp_regs[d0], s->csp_mode);
743 if (d0 == 0x83) {
744 ldebug ("0x83[%d] -> %#x\n",
745 s->csp_reg83w,
746 s->csp_reg83[s->csp_reg83w % 4]);
747 dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]);
748 s->csp_reg83w += 1;
749 }
1d14ffa9 750 else {
85571bc7 751 dsp_out_data (s, s->csp_regs[d0]);
1d14ffa9 752 }
85571bc7 753 break;
27503323 754
85571bc7
FB
755 case 0x10:
756 d0 = dsp_get_data (s);
757 dolog ("cmd 0x10 d0=%#x\n", d0);
758 break;
27503323 759
85571bc7 760 case 0x14:
15b61470 761 dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
85571bc7 762 break;
27503323
FB
763
764 case 0x40:
85571bc7
FB
765 s->time_const = dsp_get_data (s);
766 ldebug ("set time const %d\n", s->time_const);
27503323
FB
767 break;
768
85571bc7 769 case 0x41:
edd7541b
PB
770 case 0x42:
771 /*
772 * 0x41 is documented as setting the output sample rate,
773 * and 0x42 the input sample rate, but in fact SB16 hardware
774 * seems to have only a single sample rate under the hood,
775 * and FT2 sets output freq with this (go figure). Compare:
776 * http://homepages.cae.wisc.edu/~brodskye/sb16doc/sb16doc.html#SamplingRate
777 */
60e543f5 778 s->freq = restrict_sampling_rate(dsp_get_hilo(s));
85571bc7 779 ldebug ("set freq %d\n", s->freq);
27503323
FB
780 break;
781
782 case 0x48:
15b61470 783 s->block_size = dsp_get_lohi (s) + 1;
85571bc7
FB
784 ldebug ("set dma block len %d\n", s->block_size);
785 break;
786
1d14ffa9
FB
787 case 0x74:
788 case 0x75:
789 case 0x76:
790 case 0x77:
791 /* ADPCM stuff, ignore */
792 break;
793
85571bc7
FB
794 case 0x80:
795 {
15b61470 796 int freq, samples, bytes;
85571bc7
FB
797 int64_t ticks;
798
15b61470
FB
799 freq = s->freq > 0 ? s->freq : 11025;
800 samples = dsp_get_lohi (s) + 1;
85571bc7 801 bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
73bcb24d
RS
802 ticks = muldiv64(bytes, NANOSECONDS_PER_SECOND, freq);
803 if (ticks < NANOSECONDS_PER_SECOND / 1024) {
3a38d437 804 qemu_irq_raise (s->pic);
1d14ffa9
FB
805 }
806 else {
807 if (s->aux_ts) {
bc72ad67 808 timer_mod (
1d14ffa9 809 s->aux_ts,
bc72ad67 810 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks
1d14ffa9
FB
811 );
812 }
813 }
26a76461 814 ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks);
85571bc7 815 }
27503323
FB
816 break;
817
818 case 0xe0:
85571bc7
FB
819 d0 = dsp_get_data (s);
820 s->out_data_len = 0;
821 ldebug ("E0 data = %#x\n", d0);
1d14ffa9 822 dsp_out_data (s, ~d0);
d75d9f6b
FB
823 break;
824
85571bc7 825 case 0xe2:
514d97de 826#ifdef DEBUG
85571bc7 827 d0 = dsp_get_data (s);
514d97de 828 dolog ("E2 = %#x\n", d0);
829#endif
d75d9f6b
FB
830 break;
831
85571bc7
FB
832 case 0xe4:
833 s->test_reg = dsp_get_data (s);
834 break;
d75d9f6b
FB
835
836 case 0xf9:
85571bc7
FB
837 d0 = dsp_get_data (s);
838 ldebug ("command 0xf9 with %#x\n", d0);
d75d9f6b 839 switch (d0) {
85571bc7
FB
840 case 0x0e:
841 dsp_out_data (s, 0xff);
842 break;
843
844 case 0x0f:
845 dsp_out_data (s, 0x07);
846 break;
847
d75d9f6b 848 case 0x37:
85571bc7
FB
849 dsp_out_data (s, 0x38);
850 break;
851
d75d9f6b 852 default:
85571bc7
FB
853 dsp_out_data (s, 0x00);
854 break;
d75d9f6b 855 }
27503323
FB
856 break;
857
858 default:
8ec660b8
JA
859 qemu_log_mask(LOG_UNIMP, "complete: unrecognized command %#x\n",
860 s->cmd);
5e2a6443 861 return;
27503323
FB
862 }
863 }
864
85571bc7
FB
865 ldebug ("\n");
866 s->cmd = -1;
27503323
FB
867}
868
feea13e1
FB
869static void legacy_reset (SB16State *s)
870{
1ea879e5 871 struct audsettings as;
feea13e1
FB
872
873 s->freq = 11025;
874 s->fmt_signed = 0;
875 s->fmt_bits = 8;
876 s->fmt_stereo = 0;
877
878 as.freq = s->freq;
879 as.nchannels = 1;
85bc5852 880 as.fmt = AUDIO_FORMAT_U8;
d929eba5 881 as.endianness = 0;
feea13e1
FB
882
883 s->voice = AUD_open_out (
884 &s->card,
885 s->voice,
886 "sb16",
887 s,
888 SB_audio_callback,
d929eba5 889 &as
feea13e1
FB
890 );
891
892 /* Not sure about that... */
893 /* AUD_set_active_out (s->voice, 1); */
894}
895
85571bc7
FB
896static void reset (SB16State *s)
897{
3a38d437 898 qemu_irq_lower (s->pic);
85571bc7 899 if (s->dma_auto) {
3a38d437
JS
900 qemu_irq_raise (s->pic);
901 qemu_irq_lower (s->pic);
85571bc7
FB
902 }
903
904 s->mixer_regs[0x82] = 0;
905 s->dma_auto = 0;
906 s->in_index = 0;
907 s->out_data_len = 0;
908 s->left_till_irq = 0;
909 s->needed_bytes = 0;
910 s->block_size = -1;
911 s->nzero = 0;
912 s->highspeed = 0;
913 s->v2x6 = 0;
1d14ffa9 914 s->cmd = -1;
85571bc7 915
31226166 916 dsp_out_data (s, 0xaa);
85571bc7
FB
917 speaker (s, 0);
918 control (s, 0);
feea13e1 919 legacy_reset (s);
85571bc7
FB
920}
921
8307c294 922static void dsp_write(void *opaque, uint32_t nport, uint32_t val)
27503323 923{
85571bc7 924 SB16State *s = opaque;
27503323
FB
925 int iport;
926
85571bc7 927 iport = nport - s->port;
27503323 928
85571bc7 929 ldebug ("write %#x <- %#x\n", nport, val);
27503323 930 switch (iport) {
85571bc7
FB
931 case 0x06:
932 switch (val) {
933 case 0x00:
934 if (s->v2x6 == 1) {
cd7aafcb 935 reset (s);
85571bc7
FB
936 }
937 s->v2x6 = 0;
938 break;
939
940 case 0x01:
941 case 0x03: /* FreeBSD kludge */
942 s->v2x6 = 1;
943 break;
944
945 case 0xc6:
946 s->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */
947 break;
948
949 case 0xb8: /* Panic */
950 reset (s);
951 break;
952
953 case 0x39:
954 dsp_out_data (s, 0x38);
955 reset (s);
956 s->v2x6 = 0x39;
957 break;
958
959 default:
960 s->v2x6 = val;
961 break;
27503323 962 }
27503323
FB
963 break;
964
85571bc7
FB
965 case 0x0c: /* write data or command | write status */
966/* if (s->highspeed) */
967/* break; */
968
2ab5bf67 969 if (s->needed_bytes == 0) {
85571bc7
FB
970 command (s, val);
971#if 0
972 if (0 == s->needed_bytes) {
973 log_dsp (s);
27503323 974 }
85571bc7 975#endif
27503323
FB
976 }
977 else {
85571bc7 978 if (s->in_index == sizeof (s->in2_data)) {
d75d9f6b
FB
979 dolog ("in data overrun\n");
980 }
981 else {
85571bc7
FB
982 s->in2_data[s->in_index++] = val;
983 if (s->in_index == s->needed_bytes) {
984 s->needed_bytes = 0;
985 complete (s);
986#if 0
987 log_dsp (s);
988#endif
989 }
27503323
FB
990 }
991 }
992 break;
993
994 default:
85571bc7 995 ldebug ("(nport=%#x, val=%#x)\n", nport, val);
5e2a6443 996 break;
27503323
FB
997 }
998}
999
8307c294 1000static uint32_t dsp_read(void *opaque, uint32_t nport)
27503323 1001{
85571bc7
FB
1002 SB16State *s = opaque;
1003 int iport, retval, ack = 0;
27503323 1004
85571bc7 1005 iport = nport - s->port;
27503323
FB
1006
1007 switch (iport) {
85571bc7
FB
1008 case 0x06: /* reset */
1009 retval = 0xff;
d75d9f6b 1010 break;
27503323 1011
85571bc7
FB
1012 case 0x0a: /* read data */
1013 if (s->out_data_len) {
1014 retval = s->out_data[--s->out_data_len];
1015 s->last_read_byte = retval;
1016 }
1017 else {
1d14ffa9
FB
1018 if (s->cmd != -1) {
1019 dolog ("empty output buffer for command %#x\n",
1020 s->cmd);
1021 }
85571bc7 1022 retval = s->last_read_byte;
d75d9f6b 1023 /* goto error; */
27503323
FB
1024 }
1025 break;
1026
85571bc7
FB
1027 case 0x0c: /* 0 can write */
1028 retval = s->can_write ? 0 : 0x80;
27503323
FB
1029 break;
1030
85571bc7
FB
1031 case 0x0d: /* timer interrupt clear */
1032 /* dolog ("timer interrupt clear\n"); */
1033 retval = 0;
1034 break;
27503323 1035
85571bc7
FB
1036 case 0x0e: /* data available status | irq 8 ack */
1037 retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
1038 if (s->mixer_regs[0x82] & 1) {
1039 ack = 1;
9939375c 1040 s->mixer_regs[0x82] &= ~1;
3a38d437 1041 qemu_irq_lower (s->pic);
85571bc7 1042 }
27503323
FB
1043 break;
1044
85571bc7 1045 case 0x0f: /* irq 16 ack */
bc0b1dc1 1046 retval = 0xff;
85571bc7
FB
1047 if (s->mixer_regs[0x82] & 2) {
1048 ack = 1;
9939375c 1049 s->mixer_regs[0x82] &= ~2;
3a38d437 1050 qemu_irq_lower (s->pic);
85571bc7 1051 }
27503323
FB
1052 break;
1053
1054 default:
1055 goto error;
1056 }
1057
1d14ffa9 1058 if (!ack) {
85571bc7 1059 ldebug ("read %#x -> %#x\n", nport, retval);
1d14ffa9 1060 }
27503323
FB
1061
1062 return retval;
1063
1064 error:
1d14ffa9 1065 dolog ("warning: dsp_read %#x error\n", nport);
d75d9f6b 1066 return 0xff;
27503323
FB
1067}
1068
85571bc7
FB
1069static void reset_mixer (SB16State *s)
1070{
1071 int i;
1072
1073 memset (s->mixer_regs, 0xff, 0x7f);
1074 memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83);
1075
1076 s->mixer_regs[0x02] = 4; /* master volume 3bits */
1077 s->mixer_regs[0x06] = 4; /* MIDI volume 3bits */
1078 s->mixer_regs[0x08] = 0; /* CD volume 3bits */
1079 s->mixer_regs[0x0a] = 0; /* voice volume 2bits */
1080
1081 /* d5=input filt, d3=lowpass filt, d1,d2=input source */
1082 s->mixer_regs[0x0c] = 0;
1083
1084 /* d5=output filt, d1=stereo switch */
1085 s->mixer_regs[0x0e] = 0;
1086
1087 /* voice volume L d5,d7, R d1,d3 */
1088 s->mixer_regs[0x04] = (4 << 5) | (4 << 1);
1089 /* master ... */
1090 s->mixer_regs[0x22] = (4 << 5) | (4 << 1);
1091 /* MIDI ... */
1092 s->mixer_regs[0x26] = (4 << 5) | (4 << 1);
1093
1094 for (i = 0x30; i < 0x48; i++) {
1095 s->mixer_regs[i] = 0x20;
1096 }
1097}
1098
8307c294 1099static void mixer_write_indexb(void *opaque, uint32_t nport, uint32_t val)
27503323 1100{
85571bc7 1101 SB16State *s = opaque;
c0fe3827 1102 (void) nport;
85571bc7 1103 s->mixer_nreg = val;
27503323
FB
1104}
1105
8307c294 1106static void mixer_write_datab(void *opaque, uint32_t nport, uint32_t val)
27503323 1107{
85571bc7
FB
1108 SB16State *s = opaque;
1109
c0fe3827 1110 (void) nport;
85571bc7 1111 ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
202a456a 1112
85571bc7 1113 switch (s->mixer_nreg) {
d75d9f6b 1114 case 0x00:
85571bc7 1115 reset_mixer (s);
d75d9f6b
FB
1116 break;
1117
d75d9f6b 1118 case 0x80:
85571bc7
FB
1119 {
1120 int irq = irq_of_magic (val);
1121 ldebug ("setting irq to %d (val=%#x)\n", irq, val);
1d14ffa9 1122 if (irq > 0) {
85571bc7 1123 s->irq = irq;
1d14ffa9 1124 }
85571bc7 1125 }
d75d9f6b 1126 break;
27503323 1127
85571bc7
FB
1128 case 0x81:
1129 {
1130 int dma, hdma;
d75d9f6b 1131
057fa65c 1132 dma = ctz32 (val & 0xf);
1133 hdma = ctz32 (val & 0xf0);
1d14ffa9 1134 if (dma != s->dma || hdma != s->hdma) {
8ec660b8
JA
1135 qemu_log_mask(LOG_GUEST_ERROR, "attempt to change DMA 8bit"
1136 " %d(%d), 16bit %d(%d) (val=%#x)\n", dma, s->dma,
1137 hdma, s->hdma, val);
1d14ffa9 1138 }
85571bc7
FB
1139#if 0
1140 s->dma = dma;
1141 s->hdma = hdma;
1142#endif
1143 }
1144 break;
d75d9f6b 1145
85571bc7 1146 case 0x82:
8ec660b8
JA
1147 qemu_log_mask(LOG_GUEST_ERROR, "attempt to write into IRQ status"
1148 " register (val=%#x)\n", val);
85571bc7 1149 return;
d75d9f6b 1150
85571bc7 1151 default:
1d14ffa9
FB
1152 if (s->mixer_nreg >= 0x80) {
1153 ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
1154 }
85571bc7
FB
1155 break;
1156 }
1157
1158 s->mixer_regs[s->mixer_nreg] = val;
d75d9f6b
FB
1159}
1160
8307c294 1161static uint32_t mixer_read(void *opaque, uint32_t nport)
27503323 1162{
85571bc7 1163 SB16State *s = opaque;
c0fe3827
FB
1164
1165 (void) nport;
15b61470 1166#ifndef DEBUG_SB16_MOST
1d14ffa9
FB
1167 if (s->mixer_nreg != 0x82) {
1168 ldebug ("mixer_read[%#x] -> %#x\n",
1169 s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
1170 }
1171#else
85571bc7
FB
1172 ldebug ("mixer_read[%#x] -> %#x\n",
1173 s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
1d14ffa9 1174#endif
85571bc7 1175 return s->mixer_regs[s->mixer_nreg];
27503323
FB
1176}
1177
85571bc7
FB
1178static int write_audio (SB16State *s, int nchan, int dma_pos,
1179 int dma_len, int len)
27503323 1180{
f203c16e
HP
1181 IsaDma *isa_dma = nchan == s->dma ? s->isa_dma : s->isa_hdma;
1182 IsaDmaClass *k = ISADMA_GET_CLASS(isa_dma);
27503323 1183 int temp, net;
f9e92e97 1184 uint8_t tmpbuf[4096];
27503323 1185
85571bc7 1186 temp = len;
27503323
FB
1187 net = 0;
1188
1189 while (temp) {
85571bc7 1190 int left = dma_len - dma_pos;
c0fe3827
FB
1191 int copied;
1192 size_t to_copy;
27503323 1193
58935915 1194 to_copy = MIN (temp, left);
c0fe3827
FB
1195 if (to_copy > sizeof (tmpbuf)) {
1196 to_copy = sizeof (tmpbuf);
1d14ffa9 1197 }
27503323 1198
f203c16e 1199 copied = k->read_memory(isa_dma, nchan, tmpbuf, dma_pos, to_copy);
85571bc7 1200 copied = AUD_write (s->voice, tmpbuf, copied);
27503323 1201
85571bc7
FB
1202 temp -= copied;
1203 dma_pos = (dma_pos + copied) % dma_len;
27503323
FB
1204 net += copied;
1205
1d14ffa9 1206 if (!copied) {
85571bc7 1207 break;
1d14ffa9 1208 }
27503323
FB
1209 }
1210
1211 return net;
1212}
1213
85571bc7 1214static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
27503323 1215{
85571bc7 1216 SB16State *s = opaque;
1d14ffa9 1217 int till, copy, written, free;
27503323 1218
ca9cc28c 1219 if (s->block_size <= 0) {
8ec660b8
JA
1220 qemu_log_mask(LOG_GUEST_ERROR, "invalid block size=%d nchan=%d"
1221 " dma_pos=%d dma_len=%d\n", s->block_size, nchan,
1222 dma_pos, dma_len);
ca9cc28c
AZ
1223 return dma_pos;
1224 }
1225
85571bc7
FB
1226 if (s->left_till_irq < 0) {
1227 s->left_till_irq = s->block_size;
27503323
FB
1228 }
1229
1d14ffa9
FB
1230 if (s->voice) {
1231 free = s->audio_free & ~s->align;
1232 if ((free <= 0) || !dma_len) {
1233 return dma_pos;
1234 }
1235 }
1236 else {
1237 free = dma_len;
27503323
FB
1238 }
1239
85571bc7
FB
1240 copy = free;
1241 till = s->left_till_irq;
27503323 1242
d75d9f6b 1243#ifdef DEBUG_SB16_MOST
1d14ffa9
FB
1244 dolog ("pos:%06d %d till:%d len:%d\n",
1245 dma_pos, free, till, dma_len);
d75d9f6b
FB
1246#endif
1247
27503323 1248 if (till <= copy) {
2ab5bf67 1249 if (s->dma_auto == 0) {
27503323
FB
1250 copy = till;
1251 }
1252 }
1253
85571bc7
FB
1254 written = write_audio (s, nchan, dma_pos, dma_len, copy);
1255 dma_pos = (dma_pos + written) % dma_len;
1256 s->left_till_irq -= written;
27503323 1257
85571bc7
FB
1258 if (s->left_till_irq <= 0) {
1259 s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
3a38d437 1260 qemu_irq_raise (s->pic);
2ab5bf67 1261 if (s->dma_auto == 0) {
85571bc7
FB
1262 control (s, 0);
1263 speaker (s, 0);
27503323
FB
1264 }
1265 }
1266
d75d9f6b 1267#ifdef DEBUG_SB16_MOST
15b61470
FB
1268 ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
1269 dma_pos, free, dma_len, s->left_till_irq, copy, written,
1270 s->block_size);
d75d9f6b 1271#endif
27503323 1272
85571bc7
FB
1273 while (s->left_till_irq <= 0) {
1274 s->left_till_irq = s->block_size + s->left_till_irq;
27503323
FB
1275 }
1276
85571bc7 1277 return dma_pos;
27503323
FB
1278}
1279
1d14ffa9 1280static void SB_audio_callback (void *opaque, int free)
27503323 1281{
85571bc7 1282 SB16State *s = opaque;
1d14ffa9 1283 s->audio_free = free;
27503323
FB
1284}
1285
ebfd6f4d 1286static int sb16_post_load (void *opaque, int version_id)
d75d9f6b 1287{
85571bc7
FB
1288 SB16State *s = opaque;
1289
fb065187 1290 if (s->voice) {
c0fe3827 1291 AUD_close_out (&s->card, s->voice);
fb065187
FB
1292 s->voice = NULL;
1293 }
85571bc7
FB
1294
1295 if (s->dma_running) {
1d14ffa9 1296 if (s->freq) {
1ea879e5 1297 struct audsettings as;
c0fe3827 1298
1d14ffa9 1299 s->audio_free = 0;
c0fe3827
FB
1300
1301 as.freq = s->freq;
1302 as.nchannels = 1 << s->fmt_stereo;
1303 as.fmt = s->fmt;
d929eba5 1304 as.endianness = 0;
c0fe3827 1305
1d14ffa9 1306 s->voice = AUD_open_out (
c0fe3827 1307 &s->card,
1d14ffa9
FB
1308 s->voice,
1309 "sb16",
1310 s,
1311 SB_audio_callback,
d929eba5 1312 &as
1d14ffa9
FB
1313 );
1314 }
85571bc7
FB
1315
1316 control (s, 1);
1317 speaker (s, s->speaker);
d75d9f6b 1318 }
85571bc7 1319 return 0;
d75d9f6b 1320}
d75d9f6b 1321
ebfd6f4d
JQ
1322static const VMStateDescription vmstate_sb16 = {
1323 .name = "sb16",
1324 .version_id = 1,
1325 .minimum_version_id = 1,
ebfd6f4d 1326 .post_load = sb16_post_load,
d49805ae 1327 .fields = (VMStateField[]) {
cf4dc461 1328 VMSTATE_UINT32 (irq, SB16State),
1329 VMSTATE_UINT32 (dma, SB16State),
1330 VMSTATE_UINT32 (hdma, SB16State),
1331 VMSTATE_UINT32 (port, SB16State),
1332 VMSTATE_UINT32 (ver, SB16State),
1333 VMSTATE_INT32 (in_index, SB16State),
1334 VMSTATE_INT32 (out_data_len, SB16State),
1335 VMSTATE_INT32 (fmt_stereo, SB16State),
1336 VMSTATE_INT32 (fmt_signed, SB16State),
1337 VMSTATE_INT32 (fmt_bits, SB16State),
1338 VMSTATE_UINT32 (fmt, SB16State),
1339 VMSTATE_INT32 (dma_auto, SB16State),
1340 VMSTATE_INT32 (block_size, SB16State),
1341 VMSTATE_INT32 (fifo, SB16State),
1342 VMSTATE_INT32 (freq, SB16State),
1343 VMSTATE_INT32 (time_const, SB16State),
1344 VMSTATE_INT32 (speaker, SB16State),
1345 VMSTATE_INT32 (needed_bytes, SB16State),
1346 VMSTATE_INT32 (cmd, SB16State),
1347 VMSTATE_INT32 (use_hdma, SB16State),
1348 VMSTATE_INT32 (highspeed, SB16State),
1349 VMSTATE_INT32 (can_write, SB16State),
1350 VMSTATE_INT32 (v2x6, SB16State),
1351
1352 VMSTATE_UINT8 (csp_param, SB16State),
1353 VMSTATE_UINT8 (csp_value, SB16State),
1354 VMSTATE_UINT8 (csp_mode, SB16State),
1355 VMSTATE_UINT8 (csp_param, SB16State),
1356 VMSTATE_BUFFER (csp_regs, SB16State),
1357 VMSTATE_UINT8 (csp_index, SB16State),
1358 VMSTATE_BUFFER (csp_reg83, SB16State),
1359 VMSTATE_INT32 (csp_reg83r, SB16State),
1360 VMSTATE_INT32 (csp_reg83w, SB16State),
1361
1362 VMSTATE_BUFFER (in2_data, SB16State),
1363 VMSTATE_BUFFER (out_data, SB16State),
1364 VMSTATE_UINT8 (test_reg, SB16State),
1365 VMSTATE_UINT8 (last_read_byte, SB16State),
1366
1367 VMSTATE_INT32 (nzero, SB16State),
1368 VMSTATE_INT32 (left_till_irq, SB16State),
1369 VMSTATE_INT32 (dma_running, SB16State),
1370 VMSTATE_INT32 (bytes_per_second, SB16State),
1371 VMSTATE_INT32 (align, SB16State),
1372
1373 VMSTATE_INT32 (mixer_nreg, SB16State),
1374 VMSTATE_BUFFER (mixer_regs, SB16State),
1375
1376 VMSTATE_END_OF_LIST ()
ebfd6f4d
JQ
1377 }
1378};
1379
42c1a22d
RH
1380static const MemoryRegionPortio sb16_ioport_list[] = {
1381 { 4, 1, 1, .write = mixer_write_indexb },
42c1a22d
RH
1382 { 5, 1, 1, .read = mixer_read, .write = mixer_write_datab },
1383 { 6, 1, 1, .read = dsp_read, .write = dsp_write },
1384 { 10, 1, 1, .read = dsp_read },
1385 { 12, 1, 1, .write = dsp_write },
1386 { 12, 4, 1, .read = dsp_read },
cf4dc461 1387 PORTIO_END_OF_LIST (),
42c1a22d
RH
1388};
1389
1390
db895a1e 1391static void sb16_initfn (Object *obj)
27503323 1392{
db895a1e 1393 SB16State *s = SB16 (obj);
c0fe3827 1394
1d14ffa9 1395 s->cmd = -1;
db895a1e
AF
1396}
1397
1398static void sb16_realizefn (DeviceState *dev, Error **errp)
1399{
1400 ISADevice *isadev = ISA_DEVICE (dev);
1401 SB16State *s = SB16 (dev);
f203c16e 1402 IsaDmaClass *k;
db895a1e 1403
c9073238
TH
1404 s->isa_hdma = isa_get_dma(isa_bus_from_device(isadev), s->hdma);
1405 s->isa_dma = isa_get_dma(isa_bus_from_device(isadev), s->dma);
1406 if (!s->isa_dma || !s->isa_hdma) {
1407 error_setg(errp, "ISA controller does not support DMA");
1408 return;
1409 }
1410
db895a1e 1411 isa_init_irq (isadev, &s->pic, s->irq);
202a456a 1412
85571bc7
FB
1413 s->mixer_regs[0x80] = magic_of_irq (s->irq);
1414 s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
1415 s->mixer_regs[0x82] = 2 << 5;
1416
1417 s->csp_regs[5] = 1;
1418 s->csp_regs[9] = 0xf8;
1419
1420 reset_mixer (s);
bc72ad67 1421 s->aux_ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, aux_timer, s);
1d14ffa9 1422 if (!s->aux_ts) {
8ec660b8 1423 error_setg(errp, "warning: Could not create auxiliary timer");
1d14ffa9 1424 }
27503323 1425
e305a165
MAL
1426 isa_register_portio_list(isadev, &s->portio_list, s->port,
1427 sb16_ioport_list, s, "sb16");
27503323 1428
f203c16e
HP
1429 k = ISADMA_GET_CLASS(s->isa_hdma);
1430 k->register_channel(s->isa_hdma, s->hdma, SB_read_DMA, s);
1431
f203c16e
HP
1432 k = ISADMA_GET_CLASS(s->isa_dma);
1433 k->register_channel(s->isa_dma, s->dma, SB_read_DMA, s);
1434
85571bc7 1435 s->can_write = 1;
d75d9f6b 1436
1a7dafce 1437 AUD_register_card ("sb16", &s->card);
27503323 1438}
f7b4f61f 1439
39bffca2 1440static Property sb16_properties[] = {
88e47b9a 1441 DEFINE_AUDIO_PROPERTIES(SB16State, card),
c7bcc85d
PB
1442 DEFINE_PROP_UINT32 ("version", SB16State, ver, 0x0405), /* 4.5 */
1443 DEFINE_PROP_UINT32 ("iobase", SB16State, port, 0x220),
39bffca2
AL
1444 DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5),
1445 DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1),
1446 DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5),
1447 DEFINE_PROP_END_OF_LIST (),
1448};
1449
cf4dc461 1450static void sb16_class_initfn (ObjectClass *klass, void *data)
8f04ee08 1451{
cf4dc461 1452 DeviceClass *dc = DEVICE_CLASS (klass);
db895a1e
AF
1453
1454 dc->realize = sb16_realizefn;
125ee0ed 1455 set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
39bffca2
AL
1456 dc->desc = "Creative Sound Blaster 16";
1457 dc->vmsd = &vmstate_sb16;
4f67d30b 1458 device_class_set_props(dc, sb16_properties);
8f04ee08
AL
1459}
1460
8c43a6f0 1461static const TypeInfo sb16_info = {
399f05a6 1462 .name = TYPE_SB16,
39bffca2
AL
1463 .parent = TYPE_ISA_DEVICE,
1464 .instance_size = sizeof (SB16State),
db895a1e 1465 .instance_init = sb16_initfn,
39bffca2 1466 .class_init = sb16_class_initfn,
f7b4f61f
GH
1467};
1468
83f7d43a 1469static void sb16_register_types (void)
f7b4f61f 1470{
cf4dc461 1471 type_register_static (&sb16_info);
4b96159e
GH
1472 deprecated_register_soundhw("sb16", "Creative Sound Blaster 16",
1473 1, TYPE_SB16);
f7b4f61f 1474}
83f7d43a
AF
1475
1476type_init (sb16_register_types)