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