blob: 14f3e3d25218e950d7593be85c8711b00fe42cf6 [file] [log] [blame]
bellard27503322003-11-13 01:46:15 +00001/*
2 * QEMU Soundblaster 16 emulation
bellard1d14ffa2005-10-30 18:58:22 +00003 *
4 * Copyright (c) 2003-2005 Vassili Karpov (malc)
5 *
bellard27503322003-11-13 01:46:15 +00006 * 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 */
pbrook87ecb682007-11-17 17:14:51 +000024#include "hw.h"
25#include "audiodev.h"
26#include "audio/audio.h"
27#include "isa.h"
28#include "qemu-timer.h"
bellard27503322003-11-13 01:46:15 +000029
bellardfb065182004-11-09 23:09:44 +000030#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
bellard15b61472004-11-14 16:02:09 +000031
32/* #define DEBUG */
33/* #define DEBUG_SB16_MOST */
34
bellardfb065182004-11-09 23:09:44 +000035#ifdef DEBUG
36#define ldebug(...) dolog (__VA_ARGS__)
37#else
38#define ldebug(...)
39#endif
40
bellard85571bc2004-11-07 18:04:02 +000041#define IO_READ_PROTO(name) \
bellard7d977de2004-03-14 21:41:34 +000042 uint32_t name (void *opaque, uint32_t nport)
bellard85571bc2004-11-07 18:04:02 +000043#define IO_WRITE_PROTO(name) \
bellard7d977de2004-03-14 21:41:34 +000044 void name (void *opaque, uint32_t nport, uint32_t val)
bellard27503322003-11-13 01:46:15 +000045
bellard85571bc2004-11-07 18:04:02 +000046static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
bellardd329a6f2004-06-07 20:58:31 +000047
bellard27503322003-11-13 01:46:15 +000048static struct {
49 int ver_lo;
50 int ver_hi;
51 int irq;
52 int dma;
53 int hdma;
54 int port;
bellard85571bc2004-11-07 18:04:02 +000055} conf = {5, 4, 5, 1, 5, 0x220};
bellard27503322003-11-13 01:46:15 +000056
bellard5e2a6442004-03-23 22:42:11 +000057typedef struct SB16State {
bellardc0fe3822005-11-05 18:55:28 +000058 QEMUSoundCard card;
pbrookd537cf62007-04-07 18:14:41 +000059 qemu_irq *pic;
bellard85571bc2004-11-07 18:04:02 +000060 int irq;
61 int dma;
62 int hdma;
63 int port;
64 int ver;
65
bellard27503322003-11-13 01:46:15 +000066 int in_index;
67 int out_data_len;
68 int fmt_stereo;
69 int fmt_signed;
70 int fmt_bits;
bellard85571bc2004-11-07 18:04:02 +000071 audfmt_e fmt;
bellard27503322003-11-13 01:46:15 +000072 int dma_auto;
bellard85571bc2004-11-07 18:04:02 +000073 int block_size;
bellard27503322003-11-13 01:46:15 +000074 int fifo;
75 int freq;
76 int time_const;
77 int speaker;
78 int needed_bytes;
79 int cmd;
bellard27503322003-11-13 01:46:15 +000080 int use_hdma;
bellard85571bc2004-11-07 18:04:02 +000081 int highspeed;
82 int can_write;
bellard27503322003-11-13 01:46:15 +000083
84 int v2x6;
85
bellard85571bc2004-11-07 18:04:02 +000086 uint8_t csp_param;
87 uint8_t csp_value;
88 uint8_t csp_mode;
89 uint8_t csp_regs[256];
90 uint8_t csp_index;
91 uint8_t csp_reg83[4];
92 int csp_reg83r;
93 int csp_reg83w;
94
bellardd75d9f62004-10-09 17:20:54 +000095 uint8_t in2_data[10];
bellard85571bc2004-11-07 18:04:02 +000096 uint8_t out_data[50];
97 uint8_t test_reg;
98 uint8_t last_read_byte;
99 int nzero;
bellard27503322003-11-13 01:46:15 +0000100
101 int left_till_irq;
bellard27503322003-11-13 01:46:15 +0000102
bellard85571bc2004-11-07 18:04:02 +0000103 int dma_running;
104 int bytes_per_second;
105 int align;
bellard1d14ffa2005-10-30 18:58:22 +0000106 int audio_free;
107 SWVoiceOut *voice;
bellard85571bc2004-11-07 18:04:02 +0000108
bellard1d14ffa2005-10-30 18:58:22 +0000109 QEMUTimer *aux_ts;
bellard5e2a6442004-03-23 22:42:11 +0000110 /* mixer state */
111 int mixer_nreg;
bellard202a4562004-04-16 22:09:02 +0000112 uint8_t mixer_regs[256];
bellard5e2a6442004-03-23 22:42:11 +0000113} SB16State;
bellard27503322003-11-13 01:46:15 +0000114
bellard1d14ffa2005-10-30 18:58:22 +0000115static void SB_audio_callback (void *opaque, int free);
116
bellard85571bc2004-11-07 18:04:02 +0000117static int magic_of_irq (int irq)
118{
119 switch (irq) {
120 case 5:
121 return 2;
122 case 7:
123 return 4;
124 case 9:
125 return 1;
126 case 10:
127 return 8;
128 default:
129 dolog ("bad irq %d\n", irq);
130 return 2;
131 }
132}
133
134static int irq_of_magic (int magic)
135{
136 switch (magic) {
137 case 1:
138 return 9;
139 case 2:
140 return 5;
141 case 4:
142 return 7;
143 case 8:
144 return 10;
145 default:
146 dolog ("bad irq magic %d\n", magic);
147 return -1;
148 }
149}
150
151#if 0
bellard5e2a6442004-03-23 22:42:11 +0000152static void log_dsp (SB16State *dsp)
bellard27503322003-11-13 01:46:15 +0000153{
bellard85571bc2004-11-07 18:04:02 +0000154 ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
155 dsp->fmt_stereo ? "Stereo" : "Mono",
156 dsp->fmt_signed ? "Signed" : "Unsigned",
157 dsp->fmt_bits,
158 dsp->dma_auto ? "Auto" : "Single",
159 dsp->block_size,
160 dsp->freq,
161 dsp->time_const,
162 dsp->speaker);
163}
164#endif
165
166static void speaker (SB16State *s, int on)
167{
168 s->speaker = on;
169 /* AUD_enable (s->voice, on); */
bellard27503322003-11-13 01:46:15 +0000170}
171
bellard85571bc2004-11-07 18:04:02 +0000172static void control (SB16State *s, int hold)
bellard27503322003-11-13 01:46:15 +0000173{
bellard85571bc2004-11-07 18:04:02 +0000174 int dma = s->use_hdma ? s->hdma : s->dma;
175 s->dma_running = hold;
176
177 ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma);
178
bellard27503322003-11-13 01:46:15 +0000179 if (hold) {
bellard85571bc2004-11-07 18:04:02 +0000180 DMA_hold_DREQ (dma);
bellard1d14ffa2005-10-30 18:58:22 +0000181 AUD_set_active_out (s->voice, 1);
bellard27503322003-11-13 01:46:15 +0000182 }
183 else {
bellard85571bc2004-11-07 18:04:02 +0000184 DMA_release_DREQ (dma);
bellard1d14ffa2005-10-30 18:58:22 +0000185 AUD_set_active_out (s->voice, 0);
bellard27503322003-11-13 01:46:15 +0000186 }
187}
188
bellard85571bc2004-11-07 18:04:02 +0000189static void aux_timer (void *opaque)
bellard27503322003-11-13 01:46:15 +0000190{
bellard85571bc2004-11-07 18:04:02 +0000191 SB16State *s = opaque;
192 s->can_write = 1;
pbrookd537cf62007-04-07 18:14:41 +0000193 qemu_irq_raise (s->pic[s->irq]);
bellard85571bc2004-11-07 18:04:02 +0000194}
bellard27503322003-11-13 01:46:15 +0000195
bellard85571bc2004-11-07 18:04:02 +0000196#define DMA8_AUTO 1
197#define DMA8_HIGH 2
198
bellardfeea13e2006-07-04 16:49:00 +0000199static void continue_dma8 (SB16State *s)
200{
201 if (s->freq > 0) {
malc1ea879e2008-12-03 22:48:44 +0000202 struct audsettings as;
bellardfeea13e2006-07-04 16:49:00 +0000203
204 s->audio_free = 0;
205
206 as.freq = s->freq;
207 as.nchannels = 1 << s->fmt_stereo;
208 as.fmt = s->fmt;
bellardd929eba2006-07-04 21:47:22 +0000209 as.endianness = 0;
bellardfeea13e2006-07-04 16:49:00 +0000210
211 s->voice = AUD_open_out (
212 &s->card,
213 s->voice,
214 "sb16",
215 s,
216 SB_audio_callback,
bellardd929eba2006-07-04 21:47:22 +0000217 &as
bellardfeea13e2006-07-04 16:49:00 +0000218 );
219 }
220
221 control (s, 1);
222}
223
bellard85571bc2004-11-07 18:04:02 +0000224static void dma_cmd8 (SB16State *s, int mask, int dma_len)
225{
226 s->fmt = AUD_FMT_U8;
227 s->use_hdma = 0;
228 s->fmt_bits = 8;
229 s->fmt_signed = 0;
230 s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
231 if (-1 == s->time_const) {
bellardfeea13e2006-07-04 16:49:00 +0000232 if (s->freq <= 0)
233 s->freq = 11025;
bellard85571bc2004-11-07 18:04:02 +0000234 }
235 else {
236 int tmp = (256 - s->time_const);
237 s->freq = (1000000 + (tmp / 2)) / tmp;
238 }
239
bellard1d14ffa2005-10-30 18:58:22 +0000240 if (dma_len != -1) {
bellard15b61472004-11-14 16:02:09 +0000241 s->block_size = dma_len << s->fmt_stereo;
bellard1d14ffa2005-10-30 18:58:22 +0000242 }
bellard15b61472004-11-14 16:02:09 +0000243 else {
244 /* This is apparently the only way to make both Act1/PL
245 and SecondReality/FC work
246
247 Act1 sets block size via command 0x48 and it's an odd number
248 SR does the same with even number
249 Both use stereo, and Creatives own documentation states that
250 0x48 sets block size in bytes less one.. go figure */
251 s->block_size &= ~s->fmt_stereo;
252 }
bellard85571bc2004-11-07 18:04:02 +0000253
254 s->freq >>= s->fmt_stereo;
255 s->left_till_irq = s->block_size;
256 s->bytes_per_second = (s->freq << s->fmt_stereo);
257 /* s->highspeed = (mask & DMA8_HIGH) != 0; */
258 s->dma_auto = (mask & DMA8_AUTO) != 0;
259 s->align = (1 << s->fmt_stereo) - 1;
260
bellard1d14ffa2005-10-30 18:58:22 +0000261 if (s->block_size & s->align) {
262 dolog ("warning: misaligned block size %d, alignment %d\n",
263 s->block_size, s->align + 1);
264 }
bellard15b61472004-11-14 16:02:09 +0000265
bellard85571bc2004-11-07 18:04:02 +0000266 ldebug ("freq %d, stereo %d, sign %d, bits %d, "
267 "dma %d, auto %d, fifo %d, high %d\n",
268 s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
269 s->block_size, s->dma_auto, s->fifo, s->highspeed);
270
bellardfeea13e2006-07-04 16:49:00 +0000271 continue_dma8 (s);
bellard85571bc2004-11-07 18:04:02 +0000272 speaker (s, 1);
273}
274
275static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
276{
277 s->use_hdma = cmd < 0xc0;
278 s->fifo = (cmd >> 1) & 1;
279 s->dma_auto = (cmd >> 2) & 1;
280 s->fmt_signed = (d0 >> 4) & 1;
281 s->fmt_stereo = (d0 >> 5) & 1;
bellard27503322003-11-13 01:46:15 +0000282
283 switch (cmd >> 4) {
284 case 11:
bellard85571bc2004-11-07 18:04:02 +0000285 s->fmt_bits = 16;
bellard27503322003-11-13 01:46:15 +0000286 break;
287
288 case 12:
bellard85571bc2004-11-07 18:04:02 +0000289 s->fmt_bits = 8;
bellard27503322003-11-13 01:46:15 +0000290 break;
291 }
292
bellard85571bc2004-11-07 18:04:02 +0000293 if (-1 != s->time_const) {
294#if 1
295 int tmp = 256 - s->time_const;
296 s->freq = (1000000 + (tmp / 2)) / tmp;
297#else
298 /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */
299 s->freq = 1000000 / ((255 - s->time_const));
300#endif
301 s->time_const = -1;
bellard27503322003-11-13 01:46:15 +0000302 }
bellard27503322003-11-13 01:46:15 +0000303
bellard85571bc2004-11-07 18:04:02 +0000304 s->block_size = dma_len + 1;
305 s->block_size <<= (s->fmt_bits == 16);
bellard15b61472004-11-14 16:02:09 +0000306 if (!s->dma_auto) {
307 /* It is clear that for DOOM and auto-init this value
308 shouldn't take stereo into account, while Miles Sound Systems
309 setsound.exe with single transfer mode wouldn't work without it
310 wonders of SB16 yet again */
bellard85571bc2004-11-07 18:04:02 +0000311 s->block_size <<= s->fmt_stereo;
bellard15b61472004-11-14 16:02:09 +0000312 }
bellard27503322003-11-13 01:46:15 +0000313
bellard85571bc2004-11-07 18:04:02 +0000314 ldebug ("freq %d, stereo %d, sign %d, bits %d, "
315 "dma %d, auto %d, fifo %d, high %d\n",
316 s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
317 s->block_size, s->dma_auto, s->fifo, s->highspeed);
bellard27503322003-11-13 01:46:15 +0000318
bellard85571bc2004-11-07 18:04:02 +0000319 if (16 == s->fmt_bits) {
320 if (s->fmt_signed) {
321 s->fmt = AUD_FMT_S16;
bellard27503322003-11-13 01:46:15 +0000322 }
323 else {
bellard85571bc2004-11-07 18:04:02 +0000324 s->fmt = AUD_FMT_U16;
bellard27503322003-11-13 01:46:15 +0000325 }
326 }
327 else {
bellard85571bc2004-11-07 18:04:02 +0000328 if (s->fmt_signed) {
329 s->fmt = AUD_FMT_S8;
bellard27503322003-11-13 01:46:15 +0000330 }
331 else {
bellard85571bc2004-11-07 18:04:02 +0000332 s->fmt = AUD_FMT_U8;
bellard27503322003-11-13 01:46:15 +0000333 }
334 }
335
bellard85571bc2004-11-07 18:04:02 +0000336 s->left_till_irq = s->block_size;
bellard27503322003-11-13 01:46:15 +0000337
bellard85571bc2004-11-07 18:04:02 +0000338 s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16);
339 s->highspeed = 0;
340 s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1;
bellard1d14ffa2005-10-30 18:58:22 +0000341 if (s->block_size & s->align) {
342 dolog ("warning: misaligned block size %d, alignment %d\n",
343 s->block_size, s->align + 1);
344 }
bellard85571bc2004-11-07 18:04:02 +0000345
bellard1d14ffa2005-10-30 18:58:22 +0000346 if (s->freq) {
malc1ea879e2008-12-03 22:48:44 +0000347 struct audsettings as;
bellardc0fe3822005-11-05 18:55:28 +0000348
bellard1d14ffa2005-10-30 18:58:22 +0000349 s->audio_free = 0;
bellardc0fe3822005-11-05 18:55:28 +0000350
351 as.freq = s->freq;
352 as.nchannels = 1 << s->fmt_stereo;
353 as.fmt = s->fmt;
bellardd929eba2006-07-04 21:47:22 +0000354 as.endianness = 0;
bellardc0fe3822005-11-05 18:55:28 +0000355
bellard1d14ffa2005-10-30 18:58:22 +0000356 s->voice = AUD_open_out (
bellardc0fe3822005-11-05 18:55:28 +0000357 &s->card,
bellard1d14ffa2005-10-30 18:58:22 +0000358 s->voice,
359 "sb16",
360 s,
361 SB_audio_callback,
bellardd929eba2006-07-04 21:47:22 +0000362 &as
bellard1d14ffa2005-10-30 18:58:22 +0000363 );
364 }
bellard85571bc2004-11-07 18:04:02 +0000365
366 control (s, 1);
367 speaker (s, 1);
368}
369
370static inline void dsp_out_data (SB16State *s, uint8_t val)
371{
372 ldebug ("outdata %#x\n", val);
bellardc0fe3822005-11-05 18:55:28 +0000373 if ((size_t) s->out_data_len < sizeof (s->out_data)) {
bellard85571bc2004-11-07 18:04:02 +0000374 s->out_data[s->out_data_len++] = val;
bellard1d14ffa2005-10-30 18:58:22 +0000375 }
bellard85571bc2004-11-07 18:04:02 +0000376}
377
378static inline uint8_t dsp_get_data (SB16State *s)
379{
bellard1d14ffa2005-10-30 18:58:22 +0000380 if (s->in_index) {
bellard85571bc2004-11-07 18:04:02 +0000381 return s->in2_data[--s->in_index];
bellard1d14ffa2005-10-30 18:58:22 +0000382 }
bellard27503322003-11-13 01:46:15 +0000383 else {
bellard85571bc2004-11-07 18:04:02 +0000384 dolog ("buffer underflow\n");
bellardd75d9f62004-10-09 17:20:54 +0000385 return 0;
bellard85571bc2004-11-07 18:04:02 +0000386 }
bellardd75d9f62004-10-09 17:20:54 +0000387}
388
bellard85571bc2004-11-07 18:04:02 +0000389static void command (SB16State *s, uint8_t cmd)
bellard27503322003-11-13 01:46:15 +0000390{
bellard85571bc2004-11-07 18:04:02 +0000391 ldebug ("command %#x\n", cmd);
bellard27503322003-11-13 01:46:15 +0000392
393 if (cmd > 0xaf && cmd < 0xd0) {
bellard85571bc2004-11-07 18:04:02 +0000394 if (cmd & 8) {
395 dolog ("ADC not yet supported (command %#x)\n", cmd);
396 }
bellard27503322003-11-13 01:46:15 +0000397
398 switch (cmd >> 4) {
399 case 11:
400 case 12:
401 break;
402 default:
bellard85571bc2004-11-07 18:04:02 +0000403 dolog ("%#x wrong bits\n", cmd);
bellard27503322003-11-13 01:46:15 +0000404 }
bellard85571bc2004-11-07 18:04:02 +0000405 s->needed_bytes = 3;
bellard27503322003-11-13 01:46:15 +0000406 }
407 else {
bellard1d14ffa2005-10-30 18:58:22 +0000408 s->needed_bytes = 0;
409
bellard27503322003-11-13 01:46:15 +0000410 switch (cmd) {
bellardd75d9f62004-10-09 17:20:54 +0000411 case 0x03:
bellard85571bc2004-11-07 18:04:02 +0000412 dsp_out_data (s, 0x10); /* s->csp_param); */
413 goto warn;
414
bellardd329a6f2004-06-07 20:58:31 +0000415 case 0x04:
bellard85571bc2004-11-07 18:04:02 +0000416 s->needed_bytes = 1;
417 goto warn;
bellardd329a6f2004-06-07 20:58:31 +0000418
419 case 0x05:
bellard85571bc2004-11-07 18:04:02 +0000420 s->needed_bytes = 2;
421 goto warn;
422
423 case 0x08:
424 /* __asm__ ("int3"); */
425 goto warn;
bellardd75d9f62004-10-09 17:20:54 +0000426
bellardd329a6f2004-06-07 20:58:31 +0000427 case 0x0e:
bellard85571bc2004-11-07 18:04:02 +0000428 s->needed_bytes = 2;
429 goto warn;
430
431 case 0x09:
432 dsp_out_data (s, 0xf8);
433 goto warn;
bellardd329a6f2004-06-07 20:58:31 +0000434
435 case 0x0f:
bellard85571bc2004-11-07 18:04:02 +0000436 s->needed_bytes = 1;
437 goto warn;
bellardd329a6f2004-06-07 20:58:31 +0000438
bellard27503322003-11-13 01:46:15 +0000439 case 0x10:
bellard85571bc2004-11-07 18:04:02 +0000440 s->needed_bytes = 1;
441 goto warn;
bellard27503322003-11-13 01:46:15 +0000442
443 case 0x14:
bellard85571bc2004-11-07 18:04:02 +0000444 s->needed_bytes = 2;
445 s->block_size = 0;
bellard27503322003-11-13 01:46:15 +0000446 break;
447
bellard15b61472004-11-14 16:02:09 +0000448 case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */
bellardfeea13e2006-07-04 16:49:00 +0000449 dma_cmd8 (s, DMA8_AUTO, -1);
bellard15b61472004-11-14 16:02:09 +0000450 break;
451
bellard85571bc2004-11-07 18:04:02 +0000452 case 0x20: /* Direct ADC, Juice/PL */
453 dsp_out_data (s, 0xff);
454 goto warn;
bellard27503322003-11-13 01:46:15 +0000455
456 case 0x35:
bellard1d14ffa2005-10-30 18:58:22 +0000457 dolog ("0x35 - MIDI command not implemented\n");
bellard27503322003-11-13 01:46:15 +0000458 break;
459
460 case 0x40:
bellard85571bc2004-11-07 18:04:02 +0000461 s->freq = -1;
462 s->time_const = -1;
463 s->needed_bytes = 1;
bellard27503322003-11-13 01:46:15 +0000464 break;
465
466 case 0x41:
bellard85571bc2004-11-07 18:04:02 +0000467 s->freq = -1;
468 s->time_const = -1;
469 s->needed_bytes = 2;
bellard27503322003-11-13 01:46:15 +0000470 break;
471
bellard85571bc2004-11-07 18:04:02 +0000472 case 0x42:
473 s->freq = -1;
474 s->time_const = -1;
475 s->needed_bytes = 2;
476 goto warn;
477
bellardd75d9f62004-10-09 17:20:54 +0000478 case 0x45:
bellard85571bc2004-11-07 18:04:02 +0000479 dsp_out_data (s, 0xaa);
480 goto warn;
481
bellard27503322003-11-13 01:46:15 +0000482 case 0x47: /* Continue Auto-Initialize DMA 16bit */
483 break;
484
485 case 0x48:
bellard85571bc2004-11-07 18:04:02 +0000486 s->needed_bytes = 2;
bellard27503322003-11-13 01:46:15 +0000487 break;
488
bellard1d14ffa2005-10-30 18:58:22 +0000489 case 0x74:
490 s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
491 dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n");
492 break;
493
494 case 0x75: /* DMA DAC, 4-bit ADPCM Reference */
495 s->needed_bytes = 2;
496 dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n");
497 break;
498
499 case 0x76: /* DMA DAC, 2.6-bit ADPCM */
500 s->needed_bytes = 2;
501 dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n");
502 break;
503
504 case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */
505 s->needed_bytes = 2;
506 dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n");
507 break;
508
509 case 0x7d:
510 dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n");
511 dolog ("not implemented\n");
512 break;
513
514 case 0x7f:
515 dolog (
516 "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"
517 );
518 dolog ("not implemented\n");
519 break;
520
bellard27503322003-11-13 01:46:15 +0000521 case 0x80:
bellard85571bc2004-11-07 18:04:02 +0000522 s->needed_bytes = 2;
bellard27503322003-11-13 01:46:15 +0000523 break;
524
525 case 0x90:
526 case 0x91:
bellard85571bc2004-11-07 18:04:02 +0000527 dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1);
bellard27503322003-11-13 01:46:15 +0000528 break;
529
bellard85571bc2004-11-07 18:04:02 +0000530 case 0xd0: /* halt DMA operation. 8bit */
531 control (s, 0);
bellard27503322003-11-13 01:46:15 +0000532 break;
533
bellard85571bc2004-11-07 18:04:02 +0000534 case 0xd1: /* speaker on */
535 speaker (s, 1);
bellard27503322003-11-13 01:46:15 +0000536 break;
537
bellard85571bc2004-11-07 18:04:02 +0000538 case 0xd3: /* speaker off */
539 speaker (s, 0);
bellard27503322003-11-13 01:46:15 +0000540 break;
541
bellard85571bc2004-11-07 18:04:02 +0000542 case 0xd4: /* continue DMA operation. 8bit */
bellardfeea13e2006-07-04 16:49:00 +0000543 /* KQ6 (or maybe Sierras audblst.drv in general) resets
544 the frequency between halt/continue */
545 continue_dma8 (s);
bellard85571bc2004-11-07 18:04:02 +0000546 break;
bellard27503322003-11-13 01:46:15 +0000547
bellard85571bc2004-11-07 18:04:02 +0000548 case 0xd5: /* halt DMA operation. 16bit */
549 control (s, 0);
550 break;
551
552 case 0xd6: /* continue DMA operation. 16bit */
553 control (s, 1);
554 break;
555
556 case 0xd9: /* exit auto-init DMA after this block. 16bit */
557 s->dma_auto = 0;
558 break;
559
560 case 0xda: /* exit auto-init DMA after this block. 8bit */
561 s->dma_auto = 0;
bellard27503322003-11-13 01:46:15 +0000562 break;
563
bellard1d14ffa2005-10-30 18:58:22 +0000564 case 0xe0: /* DSP identification */
bellard85571bc2004-11-07 18:04:02 +0000565 s->needed_bytes = 1;
bellard1d14ffa2005-10-30 18:58:22 +0000566 break;
bellard27503322003-11-13 01:46:15 +0000567
568 case 0xe1:
bellard85571bc2004-11-07 18:04:02 +0000569 dsp_out_data (s, s->ver & 0xff);
570 dsp_out_data (s, s->ver >> 8);
571 break;
572
573 case 0xe2:
574 s->needed_bytes = 1;
575 goto warn;
bellard27503322003-11-13 01:46:15 +0000576
bellardd329a6f2004-06-07 20:58:31 +0000577 case 0xe3:
578 {
579 int i;
bellard85571bc2004-11-07 18:04:02 +0000580 for (i = sizeof (e3) - 1; i >= 0; --i)
581 dsp_out_data (s, e3[i]);
bellardd329a6f2004-06-07 20:58:31 +0000582 }
bellardd75d9f62004-10-09 17:20:54 +0000583 break;
584
bellard85571bc2004-11-07 18:04:02 +0000585 case 0xe4: /* write test reg */
586 s->needed_bytes = 1;
587 break;
588
589 case 0xe7:
590 dolog ("Attempt to probe for ESS (0xe7)?\n");
bellard1d14ffa2005-10-30 18:58:22 +0000591 break;
bellard85571bc2004-11-07 18:04:02 +0000592
bellardd75d9f62004-10-09 17:20:54 +0000593 case 0xe8: /* read test reg */
bellard85571bc2004-11-07 18:04:02 +0000594 dsp_out_data (s, s->test_reg);
bellardd75d9f62004-10-09 17:20:54 +0000595 break;
596
bellard27503322003-11-13 01:46:15 +0000597 case 0xf2:
bellard85571bc2004-11-07 18:04:02 +0000598 case 0xf3:
599 dsp_out_data (s, 0xaa);
600 s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
pbrookd537cf62007-04-07 18:14:41 +0000601 qemu_irq_raise (s->pic[s->irq]);
bellard85571bc2004-11-07 18:04:02 +0000602 break;
bellard27503322003-11-13 01:46:15 +0000603
bellardd75d9f62004-10-09 17:20:54 +0000604 case 0xf9:
bellard85571bc2004-11-07 18:04:02 +0000605 s->needed_bytes = 1;
606 goto warn;
bellardd75d9f62004-10-09 17:20:54 +0000607
608 case 0xfa:
bellard85571bc2004-11-07 18:04:02 +0000609 dsp_out_data (s, 0);
610 goto warn;
bellardd75d9f62004-10-09 17:20:54 +0000611
612 case 0xfc: /* FIXME */
bellard85571bc2004-11-07 18:04:02 +0000613 dsp_out_data (s, 0);
614 goto warn;
bellardd75d9f62004-10-09 17:20:54 +0000615
bellard27503322003-11-13 01:46:15 +0000616 default:
bellard1d14ffa2005-10-30 18:58:22 +0000617 dolog ("Unrecognized command %#x\n", cmd);
618 break;
bellard27503322003-11-13 01:46:15 +0000619 }
620 }
621
bellard1d14ffa2005-10-30 18:58:22 +0000622 if (!s->needed_bytes) {
bellard85571bc2004-11-07 18:04:02 +0000623 ldebug ("\n");
bellard1d14ffa2005-10-30 18:58:22 +0000624 }
625
626 exit:
627 if (!s->needed_bytes) {
628 s->cmd = -1;
629 }
630 else {
631 s->cmd = cmd;
632 }
bellard27503322003-11-13 01:46:15 +0000633 return;
bellard85571bc2004-11-07 18:04:02 +0000634
635 warn:
bellard81eea5e2005-08-21 09:30:54 +0000636 dolog ("warning: command %#x,%d is not truly understood yet\n",
bellard85571bc2004-11-07 18:04:02 +0000637 cmd, s->needed_bytes);
bellard1d14ffa2005-10-30 18:58:22 +0000638 goto exit;
639
bellard85571bc2004-11-07 18:04:02 +0000640}
641
642static uint16_t dsp_get_lohi (SB16State *s)
643{
644 uint8_t hi = dsp_get_data (s);
645 uint8_t lo = dsp_get_data (s);
646 return (hi << 8) | lo;
647}
648
649static uint16_t dsp_get_hilo (SB16State *s)
650{
651 uint8_t lo = dsp_get_data (s);
652 uint8_t hi = dsp_get_data (s);
653 return (hi << 8) | lo;
654}
655
656static void complete (SB16State *s)
657{
658 int d0, d1, d2;
659 ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
660 s->cmd, s->in_index, s->needed_bytes);
661
662 if (s->cmd > 0xaf && s->cmd < 0xd0) {
663 d2 = dsp_get_data (s);
664 d1 = dsp_get_data (s);
665 d0 = dsp_get_data (s);
666
667 if (s->cmd & 8) {
668 dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
669 s->cmd, d0, d1, d2);
670 }
671 else {
672 ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
673 s->cmd, d0, d1, d2);
674 dma_cmd (s, s->cmd, d0, d1 + (d2 << 8));
675 }
676 }
677 else {
678 switch (s->cmd) {
679 case 0x04:
680 s->csp_mode = dsp_get_data (s);
681 s->csp_reg83r = 0;
682 s->csp_reg83w = 0;
683 ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode);
684 break;
685
686 case 0x05:
687 s->csp_param = dsp_get_data (s);
688 s->csp_value = dsp_get_data (s);
689 ldebug ("CSP command 0x05: param=%#x value=%#x\n",
690 s->csp_param,
691 s->csp_value);
692 break;
693
694 case 0x0e:
695 d0 = dsp_get_data (s);
696 d1 = dsp_get_data (s);
697 ldebug ("write CSP register %d <- %#x\n", d1, d0);
698 if (d1 == 0x83) {
699 ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0);
700 s->csp_reg83[s->csp_reg83r % 4] = d0;
701 s->csp_reg83r += 1;
702 }
bellard1d14ffa2005-10-30 18:58:22 +0000703 else {
bellard85571bc2004-11-07 18:04:02 +0000704 s->csp_regs[d1] = d0;
bellard1d14ffa2005-10-30 18:58:22 +0000705 }
bellard85571bc2004-11-07 18:04:02 +0000706 break;
707
708 case 0x0f:
709 d0 = dsp_get_data (s);
710 ldebug ("read CSP register %#x -> %#x, mode=%#x\n",
711 d0, s->csp_regs[d0], s->csp_mode);
712 if (d0 == 0x83) {
713 ldebug ("0x83[%d] -> %#x\n",
714 s->csp_reg83w,
715 s->csp_reg83[s->csp_reg83w % 4]);
716 dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]);
717 s->csp_reg83w += 1;
718 }
bellard1d14ffa2005-10-30 18:58:22 +0000719 else {
bellard85571bc2004-11-07 18:04:02 +0000720 dsp_out_data (s, s->csp_regs[d0]);
bellard1d14ffa2005-10-30 18:58:22 +0000721 }
bellard85571bc2004-11-07 18:04:02 +0000722 break;
723
724 case 0x10:
725 d0 = dsp_get_data (s);
726 dolog ("cmd 0x10 d0=%#x\n", d0);
727 break;
728
729 case 0x14:
bellard15b61472004-11-14 16:02:09 +0000730 dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
bellard85571bc2004-11-07 18:04:02 +0000731 break;
732
733 case 0x40:
734 s->time_const = dsp_get_data (s);
735 ldebug ("set time const %d\n", s->time_const);
736 break;
737
738 case 0x42: /* FT2 sets output freq with this, go figure */
bellard1d14ffa2005-10-30 18:58:22 +0000739#if 0
bellard85571bc2004-11-07 18:04:02 +0000740 dolog ("cmd 0x42 might not do what it think it should\n");
bellard1d14ffa2005-10-30 18:58:22 +0000741#endif
bellard85571bc2004-11-07 18:04:02 +0000742 case 0x41:
743 s->freq = dsp_get_hilo (s);
744 ldebug ("set freq %d\n", s->freq);
745 break;
746
747 case 0x48:
bellard15b61472004-11-14 16:02:09 +0000748 s->block_size = dsp_get_lohi (s) + 1;
bellard85571bc2004-11-07 18:04:02 +0000749 ldebug ("set dma block len %d\n", s->block_size);
750 break;
751
bellard1d14ffa2005-10-30 18:58:22 +0000752 case 0x74:
753 case 0x75:
754 case 0x76:
755 case 0x77:
756 /* ADPCM stuff, ignore */
757 break;
758
bellard85571bc2004-11-07 18:04:02 +0000759 case 0x80:
760 {
bellard15b61472004-11-14 16:02:09 +0000761 int freq, samples, bytes;
bellard85571bc2004-11-07 18:04:02 +0000762 int64_t ticks;
763
bellard15b61472004-11-14 16:02:09 +0000764 freq = s->freq > 0 ? s->freq : 11025;
765 samples = dsp_get_lohi (s) + 1;
bellard85571bc2004-11-07 18:04:02 +0000766 bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
bellard15b61472004-11-14 16:02:09 +0000767 ticks = (bytes * ticks_per_sec) / freq;
bellard1d14ffa2005-10-30 18:58:22 +0000768 if (ticks < ticks_per_sec / 1024) {
pbrookd537cf62007-04-07 18:14:41 +0000769 qemu_irq_raise (s->pic[s->irq]);
bellard1d14ffa2005-10-30 18:58:22 +0000770 }
771 else {
772 if (s->aux_ts) {
773 qemu_mod_timer (
774 s->aux_ts,
775 qemu_get_clock (vm_clock) + ticks
776 );
777 }
778 }
bellard26a76462006-06-25 18:15:32 +0000779 ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks);
bellard85571bc2004-11-07 18:04:02 +0000780 }
781 break;
782
783 case 0xe0:
784 d0 = dsp_get_data (s);
785 s->out_data_len = 0;
786 ldebug ("E0 data = %#x\n", d0);
bellard1d14ffa2005-10-30 18:58:22 +0000787 dsp_out_data (s, ~d0);
bellard85571bc2004-11-07 18:04:02 +0000788 break;
789
790 case 0xe2:
791 d0 = dsp_get_data (s);
bellard15b61472004-11-14 16:02:09 +0000792 ldebug ("E2 = %#x\n", d0);
bellard85571bc2004-11-07 18:04:02 +0000793 break;
794
795 case 0xe4:
796 s->test_reg = dsp_get_data (s);
797 break;
798
799 case 0xf9:
800 d0 = dsp_get_data (s);
801 ldebug ("command 0xf9 with %#x\n", d0);
802 switch (d0) {
803 case 0x0e:
804 dsp_out_data (s, 0xff);
805 break;
806
807 case 0x0f:
808 dsp_out_data (s, 0x07);
809 break;
810
811 case 0x37:
812 dsp_out_data (s, 0x38);
813 break;
814
815 default:
816 dsp_out_data (s, 0x00);
817 break;
818 }
819 break;
820
821 default:
822 dolog ("complete: unrecognized command %#x\n", s->cmd);
823 return;
824 }
825 }
826
827 ldebug ("\n");
828 s->cmd = -1;
829 return;
830}
831
bellardfeea13e2006-07-04 16:49:00 +0000832static void legacy_reset (SB16State *s)
833{
malc1ea879e2008-12-03 22:48:44 +0000834 struct audsettings as;
bellardfeea13e2006-07-04 16:49:00 +0000835
836 s->freq = 11025;
837 s->fmt_signed = 0;
838 s->fmt_bits = 8;
839 s->fmt_stereo = 0;
840
841 as.freq = s->freq;
842 as.nchannels = 1;
843 as.fmt = AUD_FMT_U8;
bellardd929eba2006-07-04 21:47:22 +0000844 as.endianness = 0;
bellardfeea13e2006-07-04 16:49:00 +0000845
846 s->voice = AUD_open_out (
847 &s->card,
848 s->voice,
849 "sb16",
850 s,
851 SB_audio_callback,
bellardd929eba2006-07-04 21:47:22 +0000852 &as
bellardfeea13e2006-07-04 16:49:00 +0000853 );
854
855 /* Not sure about that... */
856 /* AUD_set_active_out (s->voice, 1); */
857}
858
bellard85571bc2004-11-07 18:04:02 +0000859static void reset (SB16State *s)
860{
pbrookd537cf62007-04-07 18:14:41 +0000861 qemu_irq_lower (s->pic[s->irq]);
bellard85571bc2004-11-07 18:04:02 +0000862 if (s->dma_auto) {
pbrookd537cf62007-04-07 18:14:41 +0000863 qemu_irq_raise (s->pic[s->irq]);
864 qemu_irq_lower (s->pic[s->irq]);
bellard85571bc2004-11-07 18:04:02 +0000865 }
866
867 s->mixer_regs[0x82] = 0;
868 s->dma_auto = 0;
869 s->in_index = 0;
870 s->out_data_len = 0;
871 s->left_till_irq = 0;
872 s->needed_bytes = 0;
873 s->block_size = -1;
874 s->nzero = 0;
875 s->highspeed = 0;
876 s->v2x6 = 0;
bellard1d14ffa2005-10-30 18:58:22 +0000877 s->cmd = -1;
bellard85571bc2004-11-07 18:04:02 +0000878
879 dsp_out_data(s, 0xaa);
880 speaker (s, 0);
881 control (s, 0);
bellardfeea13e2006-07-04 16:49:00 +0000882 legacy_reset (s);
bellard27503322003-11-13 01:46:15 +0000883}
884
885static IO_WRITE_PROTO (dsp_write)
886{
bellard85571bc2004-11-07 18:04:02 +0000887 SB16State *s = opaque;
bellard27503322003-11-13 01:46:15 +0000888 int iport;
889
bellard85571bc2004-11-07 18:04:02 +0000890 iport = nport - s->port;
bellard27503322003-11-13 01:46:15 +0000891
bellard85571bc2004-11-07 18:04:02 +0000892 ldebug ("write %#x <- %#x\n", nport, val);
bellard27503322003-11-13 01:46:15 +0000893 switch (iport) {
bellard85571bc2004-11-07 18:04:02 +0000894 case 0x06:
895 switch (val) {
896 case 0x00:
897 if (s->v2x6 == 1) {
898 if (0 && s->highspeed) {
899 s->highspeed = 0;
pbrookd537cf62007-04-07 18:14:41 +0000900 qemu_irq_lower (s->pic[s->irq]);
bellard85571bc2004-11-07 18:04:02 +0000901 control (s, 0);
902 }
bellard1d14ffa2005-10-30 18:58:22 +0000903 else {
bellard85571bc2004-11-07 18:04:02 +0000904 reset (s);
bellard1d14ffa2005-10-30 18:58:22 +0000905 }
bellard85571bc2004-11-07 18:04:02 +0000906 }
907 s->v2x6 = 0;
908 break;
909
910 case 0x01:
911 case 0x03: /* FreeBSD kludge */
912 s->v2x6 = 1;
913 break;
914
915 case 0xc6:
916 s->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */
917 break;
918
919 case 0xb8: /* Panic */
920 reset (s);
921 break;
922
923 case 0x39:
924 dsp_out_data (s, 0x38);
925 reset (s);
926 s->v2x6 = 0x39;
927 break;
928
929 default:
930 s->v2x6 = val;
931 break;
bellard27503322003-11-13 01:46:15 +0000932 }
bellard27503322003-11-13 01:46:15 +0000933 break;
934
bellard85571bc2004-11-07 18:04:02 +0000935 case 0x0c: /* write data or command | write status */
936/* if (s->highspeed) */
937/* break; */
938
939 if (0 == s->needed_bytes) {
940 command (s, val);
941#if 0
942 if (0 == s->needed_bytes) {
943 log_dsp (s);
bellard27503322003-11-13 01:46:15 +0000944 }
bellard85571bc2004-11-07 18:04:02 +0000945#endif
bellard27503322003-11-13 01:46:15 +0000946 }
947 else {
bellard85571bc2004-11-07 18:04:02 +0000948 if (s->in_index == sizeof (s->in2_data)) {
bellardd75d9f62004-10-09 17:20:54 +0000949 dolog ("in data overrun\n");
950 }
951 else {
bellard85571bc2004-11-07 18:04:02 +0000952 s->in2_data[s->in_index++] = val;
953 if (s->in_index == s->needed_bytes) {
954 s->needed_bytes = 0;
955 complete (s);
956#if 0
957 log_dsp (s);
958#endif
959 }
bellard27503322003-11-13 01:46:15 +0000960 }
961 }
962 break;
963
964 default:
bellard85571bc2004-11-07 18:04:02 +0000965 ldebug ("(nport=%#x, val=%#x)\n", nport, val);
bellard5e2a6442004-03-23 22:42:11 +0000966 break;
bellard27503322003-11-13 01:46:15 +0000967 }
968}
969
970static IO_READ_PROTO (dsp_read)
971{
bellard85571bc2004-11-07 18:04:02 +0000972 SB16State *s = opaque;
973 int iport, retval, ack = 0;
bellard27503322003-11-13 01:46:15 +0000974
bellard85571bc2004-11-07 18:04:02 +0000975 iport = nport - s->port;
bellard27503322003-11-13 01:46:15 +0000976
977 switch (iport) {
bellard85571bc2004-11-07 18:04:02 +0000978 case 0x06: /* reset */
979 retval = 0xff;
bellardd75d9f62004-10-09 17:20:54 +0000980 break;
bellard27503322003-11-13 01:46:15 +0000981
bellard85571bc2004-11-07 18:04:02 +0000982 case 0x0a: /* read data */
983 if (s->out_data_len) {
984 retval = s->out_data[--s->out_data_len];
985 s->last_read_byte = retval;
986 }
987 else {
bellard1d14ffa2005-10-30 18:58:22 +0000988 if (s->cmd != -1) {
989 dolog ("empty output buffer for command %#x\n",
990 s->cmd);
991 }
bellard85571bc2004-11-07 18:04:02 +0000992 retval = s->last_read_byte;
bellardd75d9f62004-10-09 17:20:54 +0000993 /* goto error; */
bellard27503322003-11-13 01:46:15 +0000994 }
995 break;
996
bellard85571bc2004-11-07 18:04:02 +0000997 case 0x0c: /* 0 can write */
998 retval = s->can_write ? 0 : 0x80;
999 break;
1000
1001 case 0x0d: /* timer interrupt clear */
1002 /* dolog ("timer interrupt clear\n"); */
bellard27503322003-11-13 01:46:15 +00001003 retval = 0;
1004 break;
1005
bellard85571bc2004-11-07 18:04:02 +00001006 case 0x0e: /* data available status | irq 8 ack */
1007 retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
1008 if (s->mixer_regs[0x82] & 1) {
1009 ack = 1;
1010 s->mixer_regs[0x82] &= 1;
pbrookd537cf62007-04-07 18:14:41 +00001011 qemu_irq_lower (s->pic[s->irq]);
bellard85571bc2004-11-07 18:04:02 +00001012 }
bellard27503322003-11-13 01:46:15 +00001013 break;
1014
bellard85571bc2004-11-07 18:04:02 +00001015 case 0x0f: /* irq 16 ack */
bellardbc0b1dc2004-01-18 22:19:31 +00001016 retval = 0xff;
bellard85571bc2004-11-07 18:04:02 +00001017 if (s->mixer_regs[0x82] & 2) {
1018 ack = 1;
1019 s->mixer_regs[0x82] &= 2;
pbrookd537cf62007-04-07 18:14:41 +00001020 qemu_irq_lower (s->pic[s->irq]);
bellard85571bc2004-11-07 18:04:02 +00001021 }
bellard27503322003-11-13 01:46:15 +00001022 break;
1023
1024 default:
1025 goto error;
1026 }
1027
bellard1d14ffa2005-10-30 18:58:22 +00001028 if (!ack) {
bellard85571bc2004-11-07 18:04:02 +00001029 ldebug ("read %#x -> %#x\n", nport, retval);
bellard1d14ffa2005-10-30 18:58:22 +00001030 }
bellard27503322003-11-13 01:46:15 +00001031
1032 return retval;
1033
1034 error:
bellard1d14ffa2005-10-30 18:58:22 +00001035 dolog ("warning: dsp_read %#x error\n", nport);
bellardd75d9f62004-10-09 17:20:54 +00001036 return 0xff;
bellard27503322003-11-13 01:46:15 +00001037}
1038
bellard85571bc2004-11-07 18:04:02 +00001039static void reset_mixer (SB16State *s)
1040{
1041 int i;
1042
1043 memset (s->mixer_regs, 0xff, 0x7f);
1044 memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83);
1045
1046 s->mixer_regs[0x02] = 4; /* master volume 3bits */
1047 s->mixer_regs[0x06] = 4; /* MIDI volume 3bits */
1048 s->mixer_regs[0x08] = 0; /* CD volume 3bits */
1049 s->mixer_regs[0x0a] = 0; /* voice volume 2bits */
1050
1051 /* d5=input filt, d3=lowpass filt, d1,d2=input source */
1052 s->mixer_regs[0x0c] = 0;
1053
1054 /* d5=output filt, d1=stereo switch */
1055 s->mixer_regs[0x0e] = 0;
1056
1057 /* voice volume L d5,d7, R d1,d3 */
1058 s->mixer_regs[0x04] = (4 << 5) | (4 << 1);
1059 /* master ... */
1060 s->mixer_regs[0x22] = (4 << 5) | (4 << 1);
1061 /* MIDI ... */
1062 s->mixer_regs[0x26] = (4 << 5) | (4 << 1);
1063
1064 for (i = 0x30; i < 0x48; i++) {
1065 s->mixer_regs[i] = 0x20;
1066 }
1067}
1068
bellard27503322003-11-13 01:46:15 +00001069static IO_WRITE_PROTO(mixer_write_indexb)
1070{
bellard85571bc2004-11-07 18:04:02 +00001071 SB16State *s = opaque;
bellardc0fe3822005-11-05 18:55:28 +00001072 (void) nport;
bellard85571bc2004-11-07 18:04:02 +00001073 s->mixer_nreg = val;
bellard27503322003-11-13 01:46:15 +00001074}
1075
1076static IO_WRITE_PROTO(mixer_write_datab)
1077{
bellard85571bc2004-11-07 18:04:02 +00001078 SB16State *s = opaque;
bellard202a4562004-04-16 22:09:02 +00001079
bellardc0fe3822005-11-05 18:55:28 +00001080 (void) nport;
bellard85571bc2004-11-07 18:04:02 +00001081 ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
bellard85571bc2004-11-07 18:04:02 +00001082
1083 switch (s->mixer_nreg) {
bellardd75d9f62004-10-09 17:20:54 +00001084 case 0x00:
bellard85571bc2004-11-07 18:04:02 +00001085 reset_mixer (s);
1086 break;
bellardd75d9f62004-10-09 17:20:54 +00001087
bellard85571bc2004-11-07 18:04:02 +00001088 case 0x80:
1089 {
1090 int irq = irq_of_magic (val);
1091 ldebug ("setting irq to %d (val=%#x)\n", irq, val);
bellard1d14ffa2005-10-30 18:58:22 +00001092 if (irq > 0) {
bellard85571bc2004-11-07 18:04:02 +00001093 s->irq = irq;
bellard1d14ffa2005-10-30 18:58:22 +00001094 }
bellardd75d9f62004-10-09 17:20:54 +00001095 }
1096 break;
1097
bellardd75d9f62004-10-09 17:20:54 +00001098 case 0x81:
bellard85571bc2004-11-07 18:04:02 +00001099 {
1100 int dma, hdma;
1101
1102 dma = lsbindex (val & 0xf);
1103 hdma = lsbindex (val & 0xf0);
bellard1d14ffa2005-10-30 18:58:22 +00001104 if (dma != s->dma || hdma != s->hdma) {
1105 dolog (
1106 "attempt to change DMA "
1107 "8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
1108 dma, s->dma, hdma, s->hdma, val);
1109 }
bellard85571bc2004-11-07 18:04:02 +00001110#if 0
1111 s->dma = dma;
1112 s->hdma = hdma;
1113#endif
1114 }
bellardd75d9f62004-10-09 17:20:54 +00001115 break;
bellard85571bc2004-11-07 18:04:02 +00001116
1117 case 0x82:
1118 dolog ("attempt to write into IRQ status register (val=%#x)\n",
1119 val);
bellard202a4562004-04-16 22:09:02 +00001120 return;
bellard85571bc2004-11-07 18:04:02 +00001121
1122 default:
bellard1d14ffa2005-10-30 18:58:22 +00001123 if (s->mixer_nreg >= 0x80) {
1124 ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
1125 }
bellard85571bc2004-11-07 18:04:02 +00001126 break;
bellardd75d9f62004-10-09 17:20:54 +00001127 }
bellard27503322003-11-13 01:46:15 +00001128
bellard85571bc2004-11-07 18:04:02 +00001129 s->mixer_regs[s->mixer_nreg] = val;
bellardd75d9f62004-10-09 17:20:54 +00001130}
1131
bellard27503322003-11-13 01:46:15 +00001132static IO_WRITE_PROTO(mixer_write_indexw)
1133{
bellard7d977de2004-03-14 21:41:34 +00001134 mixer_write_indexb (opaque, nport, val & 0xff);
1135 mixer_write_datab (opaque, nport, (val >> 8) & 0xff);
bellard27503322003-11-13 01:46:15 +00001136}
1137
1138static IO_READ_PROTO(mixer_read)
1139{
bellard85571bc2004-11-07 18:04:02 +00001140 SB16State *s = opaque;
bellardc0fe3822005-11-05 18:55:28 +00001141
1142 (void) nport;
bellard15b61472004-11-14 16:02:09 +00001143#ifndef DEBUG_SB16_MOST
bellard1d14ffa2005-10-30 18:58:22 +00001144 if (s->mixer_nreg != 0x82) {
1145 ldebug ("mixer_read[%#x] -> %#x\n",
1146 s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
1147 }
1148#else
bellard85571bc2004-11-07 18:04:02 +00001149 ldebug ("mixer_read[%#x] -> %#x\n",
1150 s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
bellard1d14ffa2005-10-30 18:58:22 +00001151#endif
bellard85571bc2004-11-07 18:04:02 +00001152 return s->mixer_regs[s->mixer_nreg];
bellard27503322003-11-13 01:46:15 +00001153}
1154
bellard85571bc2004-11-07 18:04:02 +00001155static int write_audio (SB16State *s, int nchan, int dma_pos,
1156 int dma_len, int len)
bellard27503322003-11-13 01:46:15 +00001157{
1158 int temp, net;
bellardf9e92e92004-02-25 23:32:01 +00001159 uint8_t tmpbuf[4096];
bellard27503322003-11-13 01:46:15 +00001160
bellard85571bc2004-11-07 18:04:02 +00001161 temp = len;
bellard27503322003-11-13 01:46:15 +00001162 net = 0;
1163
1164 while (temp) {
bellard85571bc2004-11-07 18:04:02 +00001165 int left = dma_len - dma_pos;
bellardc0fe3822005-11-05 18:55:28 +00001166 int copied;
1167 size_t to_copy;
bellard27503322003-11-13 01:46:15 +00001168
bellard85571bc2004-11-07 18:04:02 +00001169 to_copy = audio_MIN (temp, left);
bellardc0fe3822005-11-05 18:55:28 +00001170 if (to_copy > sizeof (tmpbuf)) {
1171 to_copy = sizeof (tmpbuf);
bellard1d14ffa2005-10-30 18:58:22 +00001172 }
bellard85571bc2004-11-07 18:04:02 +00001173
1174 copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
1175 copied = AUD_write (s->voice, tmpbuf, copied);
bellard27503322003-11-13 01:46:15 +00001176
1177 temp -= copied;
bellard85571bc2004-11-07 18:04:02 +00001178 dma_pos = (dma_pos + copied) % dma_len;
bellard27503322003-11-13 01:46:15 +00001179 net += copied;
1180
bellard1d14ffa2005-10-30 18:58:22 +00001181 if (!copied) {
bellard85571bc2004-11-07 18:04:02 +00001182 break;
bellard1d14ffa2005-10-30 18:58:22 +00001183 }
bellard27503322003-11-13 01:46:15 +00001184 }
1185
1186 return net;
1187}
1188
bellard85571bc2004-11-07 18:04:02 +00001189static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
bellard27503322003-11-13 01:46:15 +00001190{
bellard85571bc2004-11-07 18:04:02 +00001191 SB16State *s = opaque;
bellard1d14ffa2005-10-30 18:58:22 +00001192 int till, copy, written, free;
bellard27503322003-11-13 01:46:15 +00001193
balrogca9cc282008-01-14 04:24:29 +00001194 if (s->block_size <= 0) {
1195 dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
1196 s->block_size, nchan, dma_pos, dma_len);
1197 return dma_pos;
1198 }
1199
bellard85571bc2004-11-07 18:04:02 +00001200 if (s->left_till_irq < 0) {
1201 s->left_till_irq = s->block_size;
bellard27503322003-11-13 01:46:15 +00001202 }
1203
bellard1d14ffa2005-10-30 18:58:22 +00001204 if (s->voice) {
1205 free = s->audio_free & ~s->align;
1206 if ((free <= 0) || !dma_len) {
1207 return dma_pos;
1208 }
1209 }
1210 else {
1211 free = dma_len;
bellard27503322003-11-13 01:46:15 +00001212 }
1213
bellard85571bc2004-11-07 18:04:02 +00001214 copy = free;
1215 till = s->left_till_irq;
bellard27503322003-11-13 01:46:15 +00001216
bellardd75d9f62004-10-09 17:20:54 +00001217#ifdef DEBUG_SB16_MOST
bellard1d14ffa2005-10-30 18:58:22 +00001218 dolog ("pos:%06d %d till:%d len:%d\n",
1219 dma_pos, free, till, dma_len);
bellardd75d9f62004-10-09 17:20:54 +00001220#endif
1221
bellard27503322003-11-13 01:46:15 +00001222 if (till <= copy) {
bellard85571bc2004-11-07 18:04:02 +00001223 if (0 == s->dma_auto) {
bellard27503322003-11-13 01:46:15 +00001224 copy = till;
1225 }
1226 }
1227
bellard85571bc2004-11-07 18:04:02 +00001228 written = write_audio (s, nchan, dma_pos, dma_len, copy);
1229 dma_pos = (dma_pos + written) % dma_len;
1230 s->left_till_irq -= written;
bellard27503322003-11-13 01:46:15 +00001231
bellard85571bc2004-11-07 18:04:02 +00001232 if (s->left_till_irq <= 0) {
1233 s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
pbrookd537cf62007-04-07 18:14:41 +00001234 qemu_irq_raise (s->pic[s->irq]);
bellard85571bc2004-11-07 18:04:02 +00001235 if (0 == s->dma_auto) {
1236 control (s, 0);
1237 speaker (s, 0);
bellard27503322003-11-13 01:46:15 +00001238 }
1239 }
1240
bellardd75d9f62004-10-09 17:20:54 +00001241#ifdef DEBUG_SB16_MOST
bellard15b61472004-11-14 16:02:09 +00001242 ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
1243 dma_pos, free, dma_len, s->left_till_irq, copy, written,
1244 s->block_size);
bellardd75d9f62004-10-09 17:20:54 +00001245#endif
bellard27503322003-11-13 01:46:15 +00001246
bellard85571bc2004-11-07 18:04:02 +00001247 while (s->left_till_irq <= 0) {
1248 s->left_till_irq = s->block_size + s->left_till_irq;
bellard27503322003-11-13 01:46:15 +00001249 }
1250
bellard85571bc2004-11-07 18:04:02 +00001251 return dma_pos;
bellard27503322003-11-13 01:46:15 +00001252}
1253
bellard1d14ffa2005-10-30 18:58:22 +00001254static void SB_audio_callback (void *opaque, int free)
bellard27503322003-11-13 01:46:15 +00001255{
bellard85571bc2004-11-07 18:04:02 +00001256 SB16State *s = opaque;
bellard1d14ffa2005-10-30 18:58:22 +00001257 s->audio_free = free;
bellard27503322003-11-13 01:46:15 +00001258}
1259
bellard85571bc2004-11-07 18:04:02 +00001260static void SB_save (QEMUFile *f, void *opaque)
bellard27503322003-11-13 01:46:15 +00001261{
bellard85571bc2004-11-07 18:04:02 +00001262 SB16State *s = opaque;
bellard27503322003-11-13 01:46:15 +00001263
thsbee8d682007-12-16 23:41:11 +00001264 qemu_put_be32 (f, s->irq);
1265 qemu_put_be32 (f, s->dma);
1266 qemu_put_be32 (f, s->hdma);
1267 qemu_put_be32 (f, s->port);
1268 qemu_put_be32 (f, s->ver);
1269 qemu_put_be32 (f, s->in_index);
1270 qemu_put_be32 (f, s->out_data_len);
1271 qemu_put_be32 (f, s->fmt_stereo);
1272 qemu_put_be32 (f, s->fmt_signed);
1273 qemu_put_be32 (f, s->fmt_bits);
bellard85571bc2004-11-07 18:04:02 +00001274 qemu_put_be32s (f, &s->fmt);
thsbee8d682007-12-16 23:41:11 +00001275 qemu_put_be32 (f, s->dma_auto);
1276 qemu_put_be32 (f, s->block_size);
1277 qemu_put_be32 (f, s->fifo);
1278 qemu_put_be32 (f, s->freq);
1279 qemu_put_be32 (f, s->time_const);
1280 qemu_put_be32 (f, s->speaker);
1281 qemu_put_be32 (f, s->needed_bytes);
1282 qemu_put_be32 (f, s->cmd);
1283 qemu_put_be32 (f, s->use_hdma);
1284 qemu_put_be32 (f, s->highspeed);
1285 qemu_put_be32 (f, s->can_write);
1286 qemu_put_be32 (f, s->v2x6);
bellard85571bc2004-11-07 18:04:02 +00001287
1288 qemu_put_8s (f, &s->csp_param);
1289 qemu_put_8s (f, &s->csp_value);
1290 qemu_put_8s (f, &s->csp_mode);
1291 qemu_put_8s (f, &s->csp_param);
1292 qemu_put_buffer (f, s->csp_regs, 256);
1293 qemu_put_8s (f, &s->csp_index);
1294 qemu_put_buffer (f, s->csp_reg83, 4);
thsbee8d682007-12-16 23:41:11 +00001295 qemu_put_be32 (f, s->csp_reg83r);
1296 qemu_put_be32 (f, s->csp_reg83w);
bellard85571bc2004-11-07 18:04:02 +00001297
1298 qemu_put_buffer (f, s->in2_data, sizeof (s->in2_data));
1299 qemu_put_buffer (f, s->out_data, sizeof (s->out_data));
1300 qemu_put_8s (f, &s->test_reg);
1301 qemu_put_8s (f, &s->last_read_byte);
1302
thsbee8d682007-12-16 23:41:11 +00001303 qemu_put_be32 (f, s->nzero);
1304 qemu_put_be32 (f, s->left_till_irq);
1305 qemu_put_be32 (f, s->dma_running);
1306 qemu_put_be32 (f, s->bytes_per_second);
1307 qemu_put_be32 (f, s->align);
bellard85571bc2004-11-07 18:04:02 +00001308
thsbee8d682007-12-16 23:41:11 +00001309 qemu_put_be32 (f, s->mixer_nreg);
bellard85571bc2004-11-07 18:04:02 +00001310 qemu_put_buffer (f, s->mixer_regs, 256);
bellardd75d9f62004-10-09 17:20:54 +00001311}
1312
bellard85571bc2004-11-07 18:04:02 +00001313static int SB_load (QEMUFile *f, void *opaque, int version_id)
bellardd75d9f62004-10-09 17:20:54 +00001314{
bellard85571bc2004-11-07 18:04:02 +00001315 SB16State *s = opaque;
1316
bellard1d14ffa2005-10-30 18:58:22 +00001317 if (version_id != 1) {
bellard85571bc2004-11-07 18:04:02 +00001318 return -EINVAL;
bellard1d14ffa2005-10-30 18:58:22 +00001319 }
bellard85571bc2004-11-07 18:04:02 +00001320
thsbee8d682007-12-16 23:41:11 +00001321 s->irq=qemu_get_be32 (f);
1322 s->dma=qemu_get_be32 (f);
1323 s->hdma=qemu_get_be32 (f);
1324 s->port=qemu_get_be32 (f);
1325 s->ver=qemu_get_be32 (f);
1326 s->in_index=qemu_get_be32 (f);
1327 s->out_data_len=qemu_get_be32 (f);
1328 s->fmt_stereo=qemu_get_be32 (f);
1329 s->fmt_signed=qemu_get_be32 (f);
1330 s->fmt_bits=qemu_get_be32 (f);
bellard85571bc2004-11-07 18:04:02 +00001331 qemu_get_be32s (f, &s->fmt);
thsbee8d682007-12-16 23:41:11 +00001332 s->dma_auto=qemu_get_be32 (f);
1333 s->block_size=qemu_get_be32 (f);
1334 s->fifo=qemu_get_be32 (f);
1335 s->freq=qemu_get_be32 (f);
1336 s->time_const=qemu_get_be32 (f);
1337 s->speaker=qemu_get_be32 (f);
1338 s->needed_bytes=qemu_get_be32 (f);
1339 s->cmd=qemu_get_be32 (f);
1340 s->use_hdma=qemu_get_be32 (f);
1341 s->highspeed=qemu_get_be32 (f);
1342 s->can_write=qemu_get_be32 (f);
1343 s->v2x6=qemu_get_be32 (f);
bellard85571bc2004-11-07 18:04:02 +00001344
1345 qemu_get_8s (f, &s->csp_param);
1346 qemu_get_8s (f, &s->csp_value);
1347 qemu_get_8s (f, &s->csp_mode);
1348 qemu_get_8s (f, &s->csp_param);
1349 qemu_get_buffer (f, s->csp_regs, 256);
1350 qemu_get_8s (f, &s->csp_index);
1351 qemu_get_buffer (f, s->csp_reg83, 4);
thsbee8d682007-12-16 23:41:11 +00001352 s->csp_reg83r=qemu_get_be32 (f);
1353 s->csp_reg83w=qemu_get_be32 (f);
bellard85571bc2004-11-07 18:04:02 +00001354
1355 qemu_get_buffer (f, s->in2_data, sizeof (s->in2_data));
1356 qemu_get_buffer (f, s->out_data, sizeof (s->out_data));
1357 qemu_get_8s (f, &s->test_reg);
1358 qemu_get_8s (f, &s->last_read_byte);
1359
thsbee8d682007-12-16 23:41:11 +00001360 s->nzero=qemu_get_be32 (f);
1361 s->left_till_irq=qemu_get_be32 (f);
1362 s->dma_running=qemu_get_be32 (f);
1363 s->bytes_per_second=qemu_get_be32 (f);
1364 s->align=qemu_get_be32 (f);
bellard85571bc2004-11-07 18:04:02 +00001365
thsbee8d682007-12-16 23:41:11 +00001366 s->mixer_nreg=qemu_get_be32 (f);
bellard85571bc2004-11-07 18:04:02 +00001367 qemu_get_buffer (f, s->mixer_regs, 256);
1368
bellardfb065182004-11-09 23:09:44 +00001369 if (s->voice) {
bellardc0fe3822005-11-05 18:55:28 +00001370 AUD_close_out (&s->card, s->voice);
bellardfb065182004-11-09 23:09:44 +00001371 s->voice = NULL;
1372 }
bellard85571bc2004-11-07 18:04:02 +00001373
1374 if (s->dma_running) {
bellard1d14ffa2005-10-30 18:58:22 +00001375 if (s->freq) {
malc1ea879e2008-12-03 22:48:44 +00001376 struct audsettings as;
bellardc0fe3822005-11-05 18:55:28 +00001377
bellard1d14ffa2005-10-30 18:58:22 +00001378 s->audio_free = 0;
bellardc0fe3822005-11-05 18:55:28 +00001379
1380 as.freq = s->freq;
1381 as.nchannels = 1 << s->fmt_stereo;
1382 as.fmt = s->fmt;
bellardd929eba2006-07-04 21:47:22 +00001383 as.endianness = 0;
bellardc0fe3822005-11-05 18:55:28 +00001384
bellard1d14ffa2005-10-30 18:58:22 +00001385 s->voice = AUD_open_out (
bellardc0fe3822005-11-05 18:55:28 +00001386 &s->card,
bellard1d14ffa2005-10-30 18:58:22 +00001387 s->voice,
1388 "sb16",
1389 s,
1390 SB_audio_callback,
bellardd929eba2006-07-04 21:47:22 +00001391 &as
bellard1d14ffa2005-10-30 18:58:22 +00001392 );
1393 }
bellard85571bc2004-11-07 18:04:02 +00001394
1395 control (s, 1);
1396 speaker (s, s->speaker);
bellardd75d9f62004-10-09 17:20:54 +00001397 }
bellard85571bc2004-11-07 18:04:02 +00001398 return 0;
bellardd75d9f62004-10-09 17:20:54 +00001399}
bellardd75d9f62004-10-09 17:20:54 +00001400
pbrookd537cf62007-04-07 18:14:41 +00001401int SB16_init (AudioState *audio, qemu_irq *pic)
bellard27503322003-11-13 01:46:15 +00001402{
bellardc0fe3822005-11-05 18:55:28 +00001403 SB16State *s;
bellard27503322003-11-13 01:46:15 +00001404 int i;
1405 static const uint8_t dsp_write_ports[] = {0x6, 0xc};
1406 static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};
1407
bellardc0fe3822005-11-05 18:55:28 +00001408 if (!audio) {
1409 dolog ("No audio state\n");
1410 return -1;
1411 }
1412
1413 s = qemu_mallocz (sizeof (*s));
bellardc0fe3822005-11-05 18:55:28 +00001414
bellard1d14ffa2005-10-30 18:58:22 +00001415 s->cmd = -1;
pbrookd537cf62007-04-07 18:14:41 +00001416 s->pic = pic;
bellard85571bc2004-11-07 18:04:02 +00001417 s->irq = conf.irq;
1418 s->dma = conf.dma;
1419 s->hdma = conf.hdma;
1420 s->port = conf.port;
1421 s->ver = conf.ver_lo | (conf.ver_hi << 8);
bellard27503322003-11-13 01:46:15 +00001422
bellard85571bc2004-11-07 18:04:02 +00001423 s->mixer_regs[0x80] = magic_of_irq (s->irq);
1424 s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
1425 s->mixer_regs[0x82] = 2 << 5;
1426
1427 s->csp_regs[5] = 1;
1428 s->csp_regs[9] = 0xf8;
1429
1430 reset_mixer (s);
1431 s->aux_ts = qemu_new_timer (vm_clock, aux_timer, s);
bellard1d14ffa2005-10-30 18:58:22 +00001432 if (!s->aux_ts) {
bellardc0fe3822005-11-05 18:55:28 +00001433 dolog ("warning: Could not create auxiliary timer\n");
bellard1d14ffa2005-10-30 18:58:22 +00001434 }
bellard27503322003-11-13 01:46:15 +00001435
malcb1503cd2008-12-22 20:33:55 +00001436 for (i = 0; i < ARRAY_SIZE (dsp_write_ports); i++) {
bellard85571bc2004-11-07 18:04:02 +00001437 register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s);
bellard27503322003-11-13 01:46:15 +00001438 }
1439
malcb1503cd2008-12-22 20:33:55 +00001440 for (i = 0; i < ARRAY_SIZE (dsp_read_ports); i++) {
bellard85571bc2004-11-07 18:04:02 +00001441 register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s);
bellardd75d9f62004-10-09 17:20:54 +00001442 }
1443
bellard85571bc2004-11-07 18:04:02 +00001444 register_ioport_write (s->port + 0x4, 1, 1, mixer_write_indexb, s);
1445 register_ioport_write (s->port + 0x4, 1, 2, mixer_write_indexw, s);
1446 register_ioport_read (s->port + 0x5, 1, 1, mixer_read, s);
1447 register_ioport_write (s->port + 0x5, 1, 1, mixer_write_datab, s);
1448
1449 DMA_register_channel (s->hdma, SB_read_DMA, s);
1450 DMA_register_channel (s->dma, SB_read_DMA, s);
1451 s->can_write = 1;
1452
bellard85571bc2004-11-07 18:04:02 +00001453 register_savevm ("sb16", 0, 1, SB_save, SB_load, s);
bellardc0fe3822005-11-05 18:55:28 +00001454 AUD_register_card (audio, "sb16", &s->card);
1455 return 0;
bellard27503322003-11-13 01:46:15 +00001456}