blob: 995435f2404b5762ace4a09ae252471d6bcc1609 [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 */
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010024#include "hw/hw.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010025#include "hw/audio/audio.h"
pbrook87ecb682007-11-17 17:14:51 +000026#include "audio/audio.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010027#include "hw/isa/isa.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010028#include "hw/qdev.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010029#include "qemu/timer.h"
30#include "qemu/host-utils.h"
bellard27503322003-11-13 01:46:15 +000031
bellardfb065182004-11-09 23:09:44 +000032#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
bellard15b61472004-11-14 16:02:09 +000033
34/* #define DEBUG */
35/* #define DEBUG_SB16_MOST */
36
bellardfb065182004-11-09 23:09:44 +000037#ifdef DEBUG
38#define ldebug(...) dolog (__VA_ARGS__)
39#else
40#define ldebug(...)
41#endif
42
bellard85571bc2004-11-07 18:04:02 +000043static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
bellardd329a6f2004-06-07 20:58:31 +000044
Andreas Färber399f05a2013-04-27 22:18:49 +020045#define TYPE_SB16 "sb16"
46#define SB16(obj) OBJECT_CHECK (SB16State, (obj), TYPE_SB16)
47
bellard5e2a6442004-03-23 22:42:11 +000048typedef struct SB16State {
Andreas Färber399f05a2013-04-27 22:18:49 +020049 ISADevice parent_obj;
50
bellardc0fe3822005-11-05 18:55:28 +000051 QEMUSoundCard card;
Jes Sorensen3a38d432009-08-14 11:36:15 +020052 qemu_irq pic;
Gerd Hoffmannf7b4f612009-09-10 11:43:30 +020053 uint32_t irq;
54 uint32_t dma;
55 uint32_t hdma;
56 uint32_t port;
57 uint32_t ver;
bellard85571bc2004-11-07 18:04:02 +000058
bellard27503322003-11-13 01:46:15 +000059 int in_index;
60 int out_data_len;
61 int fmt_stereo;
62 int fmt_signed;
63 int fmt_bits;
bellard85571bc2004-11-07 18:04:02 +000064 audfmt_e fmt;
bellard27503322003-11-13 01:46:15 +000065 int dma_auto;
bellard85571bc2004-11-07 18:04:02 +000066 int block_size;
bellard27503322003-11-13 01:46:15 +000067 int fifo;
68 int freq;
69 int time_const;
70 int speaker;
71 int needed_bytes;
72 int cmd;
bellard27503322003-11-13 01:46:15 +000073 int use_hdma;
bellard85571bc2004-11-07 18:04:02 +000074 int highspeed;
75 int can_write;
bellard27503322003-11-13 01:46:15 +000076
77 int v2x6;
78
bellard85571bc2004-11-07 18:04:02 +000079 uint8_t csp_param;
80 uint8_t csp_value;
81 uint8_t csp_mode;
82 uint8_t csp_regs[256];
83 uint8_t csp_index;
84 uint8_t csp_reg83[4];
85 int csp_reg83r;
86 int csp_reg83w;
87
bellardd75d9f62004-10-09 17:20:54 +000088 uint8_t in2_data[10];
bellard85571bc2004-11-07 18:04:02 +000089 uint8_t out_data[50];
90 uint8_t test_reg;
91 uint8_t last_read_byte;
92 int nzero;
bellard27503322003-11-13 01:46:15 +000093
94 int left_till_irq;
bellard27503322003-11-13 01:46:15 +000095
bellard85571bc2004-11-07 18:04:02 +000096 int dma_running;
97 int bytes_per_second;
98 int align;
bellard1d14ffa2005-10-30 18:58:22 +000099 int audio_free;
100 SWVoiceOut *voice;
bellard85571bc2004-11-07 18:04:02 +0000101
bellard1d14ffa2005-10-30 18:58:22 +0000102 QEMUTimer *aux_ts;
bellard5e2a6442004-03-23 22:42:11 +0000103 /* mixer state */
104 int mixer_nreg;
bellard202a4562004-04-16 22:09:02 +0000105 uint8_t mixer_regs[256];
bellard5e2a6442004-03-23 22:42:11 +0000106} SB16State;
bellard27503322003-11-13 01:46:15 +0000107
bellard1d14ffa2005-10-30 18:58:22 +0000108static void SB_audio_callback (void *opaque, int free);
109
bellard85571bc2004-11-07 18:04:02 +0000110static int magic_of_irq (int irq)
111{
112 switch (irq) {
113 case 5:
114 return 2;
115 case 7:
116 return 4;
117 case 9:
118 return 1;
119 case 10:
120 return 8;
121 default:
122 dolog ("bad irq %d\n", irq);
123 return 2;
124 }
125}
126
127static int irq_of_magic (int magic)
128{
129 switch (magic) {
130 case 1:
131 return 9;
132 case 2:
133 return 5;
134 case 4:
135 return 7;
136 case 8:
137 return 10;
138 default:
139 dolog ("bad irq magic %d\n", magic);
140 return -1;
141 }
142}
143
144#if 0
bellard5e2a6442004-03-23 22:42:11 +0000145static void log_dsp (SB16State *dsp)
bellard27503322003-11-13 01:46:15 +0000146{
bellard85571bc2004-11-07 18:04:02 +0000147 ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
148 dsp->fmt_stereo ? "Stereo" : "Mono",
149 dsp->fmt_signed ? "Signed" : "Unsigned",
150 dsp->fmt_bits,
151 dsp->dma_auto ? "Auto" : "Single",
152 dsp->block_size,
153 dsp->freq,
154 dsp->time_const,
155 dsp->speaker);
156}
157#endif
158
159static void speaker (SB16State *s, int on)
160{
161 s->speaker = on;
162 /* AUD_enable (s->voice, on); */
bellard27503322003-11-13 01:46:15 +0000163}
164
bellard85571bc2004-11-07 18:04:02 +0000165static void control (SB16State *s, int hold)
bellard27503322003-11-13 01:46:15 +0000166{
bellard85571bc2004-11-07 18:04:02 +0000167 int dma = s->use_hdma ? s->hdma : s->dma;
168 s->dma_running = hold;
169
170 ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma);
171
bellard27503322003-11-13 01:46:15 +0000172 if (hold) {
bellard85571bc2004-11-07 18:04:02 +0000173 DMA_hold_DREQ (dma);
bellard1d14ffa2005-10-30 18:58:22 +0000174 AUD_set_active_out (s->voice, 1);
bellard27503322003-11-13 01:46:15 +0000175 }
176 else {
bellard85571bc2004-11-07 18:04:02 +0000177 DMA_release_DREQ (dma);
bellard1d14ffa2005-10-30 18:58:22 +0000178 AUD_set_active_out (s->voice, 0);
bellard27503322003-11-13 01:46:15 +0000179 }
180}
181
bellard85571bc2004-11-07 18:04:02 +0000182static void aux_timer (void *opaque)
bellard27503322003-11-13 01:46:15 +0000183{
bellard85571bc2004-11-07 18:04:02 +0000184 SB16State *s = opaque;
185 s->can_write = 1;
Jes Sorensen3a38d432009-08-14 11:36:15 +0200186 qemu_irq_raise (s->pic);
bellard85571bc2004-11-07 18:04:02 +0000187}
bellard27503322003-11-13 01:46:15 +0000188
bellard85571bc2004-11-07 18:04:02 +0000189#define DMA8_AUTO 1
190#define DMA8_HIGH 2
191
bellardfeea13e2006-07-04 16:49:00 +0000192static void continue_dma8 (SB16State *s)
193{
194 if (s->freq > 0) {
malc1ea879e2008-12-03 22:48:44 +0000195 struct audsettings as;
bellardfeea13e2006-07-04 16:49:00 +0000196
197 s->audio_free = 0;
198
199 as.freq = s->freq;
200 as.nchannels = 1 << s->fmt_stereo;
201 as.fmt = s->fmt;
bellardd929eba2006-07-04 21:47:22 +0000202 as.endianness = 0;
bellardfeea13e2006-07-04 16:49:00 +0000203
204 s->voice = AUD_open_out (
205 &s->card,
206 s->voice,
207 "sb16",
208 s,
209 SB_audio_callback,
bellardd929eba2006-07-04 21:47:22 +0000210 &as
bellardfeea13e2006-07-04 16:49:00 +0000211 );
212 }
213
214 control (s, 1);
215}
216
bellard85571bc2004-11-07 18:04:02 +0000217static void dma_cmd8 (SB16State *s, int mask, int dma_len)
218{
219 s->fmt = AUD_FMT_U8;
220 s->use_hdma = 0;
221 s->fmt_bits = 8;
222 s->fmt_signed = 0;
223 s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
224 if (-1 == s->time_const) {
bellardfeea13e2006-07-04 16:49:00 +0000225 if (s->freq <= 0)
226 s->freq = 11025;
bellard85571bc2004-11-07 18:04:02 +0000227 }
228 else {
229 int tmp = (256 - s->time_const);
230 s->freq = (1000000 + (tmp / 2)) / tmp;
231 }
232
bellard1d14ffa2005-10-30 18:58:22 +0000233 if (dma_len != -1) {
bellard15b61472004-11-14 16:02:09 +0000234 s->block_size = dma_len << s->fmt_stereo;
bellard1d14ffa2005-10-30 18:58:22 +0000235 }
bellard15b61472004-11-14 16:02:09 +0000236 else {
237 /* This is apparently the only way to make both Act1/PL
238 and SecondReality/FC work
239
240 Act1 sets block size via command 0x48 and it's an odd number
241 SR does the same with even number
242 Both use stereo, and Creatives own documentation states that
243 0x48 sets block size in bytes less one.. go figure */
244 s->block_size &= ~s->fmt_stereo;
245 }
bellard85571bc2004-11-07 18:04:02 +0000246
247 s->freq >>= s->fmt_stereo;
248 s->left_till_irq = s->block_size;
249 s->bytes_per_second = (s->freq << s->fmt_stereo);
250 /* s->highspeed = (mask & DMA8_HIGH) != 0; */
251 s->dma_auto = (mask & DMA8_AUTO) != 0;
252 s->align = (1 << s->fmt_stereo) - 1;
253
bellard1d14ffa2005-10-30 18:58:22 +0000254 if (s->block_size & s->align) {
255 dolog ("warning: misaligned block size %d, alignment %d\n",
256 s->block_size, s->align + 1);
257 }
bellard15b61472004-11-14 16:02:09 +0000258
bellard85571bc2004-11-07 18:04:02 +0000259 ldebug ("freq %d, stereo %d, sign %d, bits %d, "
260 "dma %d, auto %d, fifo %d, high %d\n",
261 s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
262 s->block_size, s->dma_auto, s->fifo, s->highspeed);
263
bellardfeea13e2006-07-04 16:49:00 +0000264 continue_dma8 (s);
bellard85571bc2004-11-07 18:04:02 +0000265 speaker (s, 1);
266}
267
268static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
269{
270 s->use_hdma = cmd < 0xc0;
271 s->fifo = (cmd >> 1) & 1;
272 s->dma_auto = (cmd >> 2) & 1;
273 s->fmt_signed = (d0 >> 4) & 1;
274 s->fmt_stereo = (d0 >> 5) & 1;
bellard27503322003-11-13 01:46:15 +0000275
276 switch (cmd >> 4) {
277 case 11:
bellard85571bc2004-11-07 18:04:02 +0000278 s->fmt_bits = 16;
bellard27503322003-11-13 01:46:15 +0000279 break;
280
281 case 12:
bellard85571bc2004-11-07 18:04:02 +0000282 s->fmt_bits = 8;
bellard27503322003-11-13 01:46:15 +0000283 break;
284 }
285
bellard85571bc2004-11-07 18:04:02 +0000286 if (-1 != s->time_const) {
287#if 1
288 int tmp = 256 - s->time_const;
289 s->freq = (1000000 + (tmp / 2)) / tmp;
290#else
291 /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */
292 s->freq = 1000000 / ((255 - s->time_const));
293#endif
294 s->time_const = -1;
bellard27503322003-11-13 01:46:15 +0000295 }
bellard27503322003-11-13 01:46:15 +0000296
bellard85571bc2004-11-07 18:04:02 +0000297 s->block_size = dma_len + 1;
298 s->block_size <<= (s->fmt_bits == 16);
bellard15b61472004-11-14 16:02:09 +0000299 if (!s->dma_auto) {
300 /* It is clear that for DOOM and auto-init this value
301 shouldn't take stereo into account, while Miles Sound Systems
302 setsound.exe with single transfer mode wouldn't work without it
303 wonders of SB16 yet again */
bellard85571bc2004-11-07 18:04:02 +0000304 s->block_size <<= s->fmt_stereo;
bellard15b61472004-11-14 16:02:09 +0000305 }
bellard27503322003-11-13 01:46:15 +0000306
bellard85571bc2004-11-07 18:04:02 +0000307 ldebug ("freq %d, stereo %d, sign %d, bits %d, "
308 "dma %d, auto %d, fifo %d, high %d\n",
309 s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
310 s->block_size, s->dma_auto, s->fifo, s->highspeed);
bellard27503322003-11-13 01:46:15 +0000311
bellard85571bc2004-11-07 18:04:02 +0000312 if (16 == s->fmt_bits) {
313 if (s->fmt_signed) {
314 s->fmt = AUD_FMT_S16;
bellard27503322003-11-13 01:46:15 +0000315 }
316 else {
bellard85571bc2004-11-07 18:04:02 +0000317 s->fmt = AUD_FMT_U16;
bellard27503322003-11-13 01:46:15 +0000318 }
319 }
320 else {
bellard85571bc2004-11-07 18:04:02 +0000321 if (s->fmt_signed) {
322 s->fmt = AUD_FMT_S8;
bellard27503322003-11-13 01:46:15 +0000323 }
324 else {
bellard85571bc2004-11-07 18:04:02 +0000325 s->fmt = AUD_FMT_U8;
bellard27503322003-11-13 01:46:15 +0000326 }
327 }
328
bellard85571bc2004-11-07 18:04:02 +0000329 s->left_till_irq = s->block_size;
bellard27503322003-11-13 01:46:15 +0000330
bellard85571bc2004-11-07 18:04:02 +0000331 s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16);
332 s->highspeed = 0;
333 s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1;
bellard1d14ffa2005-10-30 18:58:22 +0000334 if (s->block_size & s->align) {
335 dolog ("warning: misaligned block size %d, alignment %d\n",
336 s->block_size, s->align + 1);
337 }
bellard85571bc2004-11-07 18:04:02 +0000338
bellard1d14ffa2005-10-30 18:58:22 +0000339 if (s->freq) {
malc1ea879e2008-12-03 22:48:44 +0000340 struct audsettings as;
bellardc0fe3822005-11-05 18:55:28 +0000341
bellard1d14ffa2005-10-30 18:58:22 +0000342 s->audio_free = 0;
bellardc0fe3822005-11-05 18:55:28 +0000343
344 as.freq = s->freq;
345 as.nchannels = 1 << s->fmt_stereo;
346 as.fmt = s->fmt;
bellardd929eba2006-07-04 21:47:22 +0000347 as.endianness = 0;
bellardc0fe3822005-11-05 18:55:28 +0000348
bellard1d14ffa2005-10-30 18:58:22 +0000349 s->voice = AUD_open_out (
bellardc0fe3822005-11-05 18:55:28 +0000350 &s->card,
bellard1d14ffa2005-10-30 18:58:22 +0000351 s->voice,
352 "sb16",
353 s,
354 SB_audio_callback,
bellardd929eba2006-07-04 21:47:22 +0000355 &as
bellard1d14ffa2005-10-30 18:58:22 +0000356 );
357 }
bellard85571bc2004-11-07 18:04:02 +0000358
359 control (s, 1);
360 speaker (s, 1);
361}
362
363static inline void dsp_out_data (SB16State *s, uint8_t val)
364{
365 ldebug ("outdata %#x\n", val);
bellardc0fe3822005-11-05 18:55:28 +0000366 if ((size_t) s->out_data_len < sizeof (s->out_data)) {
bellard85571bc2004-11-07 18:04:02 +0000367 s->out_data[s->out_data_len++] = val;
bellard1d14ffa2005-10-30 18:58:22 +0000368 }
bellard85571bc2004-11-07 18:04:02 +0000369}
370
371static inline uint8_t dsp_get_data (SB16State *s)
372{
bellard1d14ffa2005-10-30 18:58:22 +0000373 if (s->in_index) {
bellard85571bc2004-11-07 18:04:02 +0000374 return s->in2_data[--s->in_index];
bellard1d14ffa2005-10-30 18:58:22 +0000375 }
bellard27503322003-11-13 01:46:15 +0000376 else {
bellard85571bc2004-11-07 18:04:02 +0000377 dolog ("buffer underflow\n");
bellardd75d9f62004-10-09 17:20:54 +0000378 return 0;
bellard85571bc2004-11-07 18:04:02 +0000379 }
bellardd75d9f62004-10-09 17:20:54 +0000380}
381
bellard85571bc2004-11-07 18:04:02 +0000382static void command (SB16State *s, uint8_t cmd)
bellard27503322003-11-13 01:46:15 +0000383{
bellard85571bc2004-11-07 18:04:02 +0000384 ldebug ("command %#x\n", cmd);
bellard27503322003-11-13 01:46:15 +0000385
386 if (cmd > 0xaf && cmd < 0xd0) {
bellard85571bc2004-11-07 18:04:02 +0000387 if (cmd & 8) {
388 dolog ("ADC not yet supported (command %#x)\n", cmd);
389 }
bellard27503322003-11-13 01:46:15 +0000390
391 switch (cmd >> 4) {
392 case 11:
393 case 12:
394 break;
395 default:
bellard85571bc2004-11-07 18:04:02 +0000396 dolog ("%#x wrong bits\n", cmd);
bellard27503322003-11-13 01:46:15 +0000397 }
bellard85571bc2004-11-07 18:04:02 +0000398 s->needed_bytes = 3;
bellard27503322003-11-13 01:46:15 +0000399 }
400 else {
bellard1d14ffa2005-10-30 18:58:22 +0000401 s->needed_bytes = 0;
402
bellard27503322003-11-13 01:46:15 +0000403 switch (cmd) {
bellardd75d9f62004-10-09 17:20:54 +0000404 case 0x03:
bellard85571bc2004-11-07 18:04:02 +0000405 dsp_out_data (s, 0x10); /* s->csp_param); */
406 goto warn;
407
bellardd329a6f2004-06-07 20:58:31 +0000408 case 0x04:
bellard85571bc2004-11-07 18:04:02 +0000409 s->needed_bytes = 1;
410 goto warn;
bellardd329a6f2004-06-07 20:58:31 +0000411
412 case 0x05:
bellard85571bc2004-11-07 18:04:02 +0000413 s->needed_bytes = 2;
414 goto warn;
415
416 case 0x08:
417 /* __asm__ ("int3"); */
418 goto warn;
bellardd75d9f62004-10-09 17:20:54 +0000419
bellardd329a6f2004-06-07 20:58:31 +0000420 case 0x0e:
bellard85571bc2004-11-07 18:04:02 +0000421 s->needed_bytes = 2;
422 goto warn;
423
424 case 0x09:
425 dsp_out_data (s, 0xf8);
426 goto warn;
bellardd329a6f2004-06-07 20:58:31 +0000427
428 case 0x0f:
bellard85571bc2004-11-07 18:04:02 +0000429 s->needed_bytes = 1;
430 goto warn;
bellardd329a6f2004-06-07 20:58:31 +0000431
bellard27503322003-11-13 01:46:15 +0000432 case 0x10:
bellard85571bc2004-11-07 18:04:02 +0000433 s->needed_bytes = 1;
434 goto warn;
bellard27503322003-11-13 01:46:15 +0000435
436 case 0x14:
bellard85571bc2004-11-07 18:04:02 +0000437 s->needed_bytes = 2;
438 s->block_size = 0;
bellard27503322003-11-13 01:46:15 +0000439 break;
440
bellard15b61472004-11-14 16:02:09 +0000441 case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */
bellardfeea13e2006-07-04 16:49:00 +0000442 dma_cmd8 (s, DMA8_AUTO, -1);
bellard15b61472004-11-14 16:02:09 +0000443 break;
444
bellard85571bc2004-11-07 18:04:02 +0000445 case 0x20: /* Direct ADC, Juice/PL */
446 dsp_out_data (s, 0xff);
447 goto warn;
bellard27503322003-11-13 01:46:15 +0000448
449 case 0x35:
bellard1d14ffa2005-10-30 18:58:22 +0000450 dolog ("0x35 - MIDI command not implemented\n");
bellard27503322003-11-13 01:46:15 +0000451 break;
452
453 case 0x40:
bellard85571bc2004-11-07 18:04:02 +0000454 s->freq = -1;
455 s->time_const = -1;
456 s->needed_bytes = 1;
bellard27503322003-11-13 01:46:15 +0000457 break;
458
459 case 0x41:
bellard85571bc2004-11-07 18:04:02 +0000460 s->freq = -1;
461 s->time_const = -1;
462 s->needed_bytes = 2;
bellard27503322003-11-13 01:46:15 +0000463 break;
464
bellard85571bc2004-11-07 18:04:02 +0000465 case 0x42:
466 s->freq = -1;
467 s->time_const = -1;
468 s->needed_bytes = 2;
469 goto warn;
470
bellardd75d9f62004-10-09 17:20:54 +0000471 case 0x45:
bellard85571bc2004-11-07 18:04:02 +0000472 dsp_out_data (s, 0xaa);
473 goto warn;
474
bellard27503322003-11-13 01:46:15 +0000475 case 0x47: /* Continue Auto-Initialize DMA 16bit */
476 break;
477
478 case 0x48:
bellard85571bc2004-11-07 18:04:02 +0000479 s->needed_bytes = 2;
bellard27503322003-11-13 01:46:15 +0000480 break;
481
bellard1d14ffa2005-10-30 18:58:22 +0000482 case 0x74:
483 s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
484 dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n");
485 break;
486
487 case 0x75: /* DMA DAC, 4-bit ADPCM Reference */
488 s->needed_bytes = 2;
489 dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n");
490 break;
491
492 case 0x76: /* DMA DAC, 2.6-bit ADPCM */
493 s->needed_bytes = 2;
494 dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n");
495 break;
496
497 case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */
498 s->needed_bytes = 2;
499 dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n");
500 break;
501
502 case 0x7d:
503 dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n");
504 dolog ("not implemented\n");
505 break;
506
507 case 0x7f:
508 dolog (
509 "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"
510 );
511 dolog ("not implemented\n");
512 break;
513
bellard27503322003-11-13 01:46:15 +0000514 case 0x80:
bellard85571bc2004-11-07 18:04:02 +0000515 s->needed_bytes = 2;
bellard27503322003-11-13 01:46:15 +0000516 break;
517
518 case 0x90:
519 case 0x91:
bellard85571bc2004-11-07 18:04:02 +0000520 dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1);
bellard27503322003-11-13 01:46:15 +0000521 break;
522
bellard85571bc2004-11-07 18:04:02 +0000523 case 0xd0: /* halt DMA operation. 8bit */
524 control (s, 0);
bellard27503322003-11-13 01:46:15 +0000525 break;
526
bellard85571bc2004-11-07 18:04:02 +0000527 case 0xd1: /* speaker on */
528 speaker (s, 1);
bellard27503322003-11-13 01:46:15 +0000529 break;
530
bellard85571bc2004-11-07 18:04:02 +0000531 case 0xd3: /* speaker off */
532 speaker (s, 0);
bellard27503322003-11-13 01:46:15 +0000533 break;
534
bellard85571bc2004-11-07 18:04:02 +0000535 case 0xd4: /* continue DMA operation. 8bit */
bellardfeea13e2006-07-04 16:49:00 +0000536 /* KQ6 (or maybe Sierras audblst.drv in general) resets
537 the frequency between halt/continue */
538 continue_dma8 (s);
bellard85571bc2004-11-07 18:04:02 +0000539 break;
bellard27503322003-11-13 01:46:15 +0000540
bellard85571bc2004-11-07 18:04:02 +0000541 case 0xd5: /* halt DMA operation. 16bit */
542 control (s, 0);
543 break;
544
545 case 0xd6: /* continue DMA operation. 16bit */
546 control (s, 1);
547 break;
548
549 case 0xd9: /* exit auto-init DMA after this block. 16bit */
550 s->dma_auto = 0;
551 break;
552
553 case 0xda: /* exit auto-init DMA after this block. 8bit */
554 s->dma_auto = 0;
bellard27503322003-11-13 01:46:15 +0000555 break;
556
bellard1d14ffa2005-10-30 18:58:22 +0000557 case 0xe0: /* DSP identification */
bellard85571bc2004-11-07 18:04:02 +0000558 s->needed_bytes = 1;
bellard1d14ffa2005-10-30 18:58:22 +0000559 break;
bellard27503322003-11-13 01:46:15 +0000560
561 case 0xe1:
bellard85571bc2004-11-07 18:04:02 +0000562 dsp_out_data (s, s->ver & 0xff);
563 dsp_out_data (s, s->ver >> 8);
564 break;
565
566 case 0xe2:
567 s->needed_bytes = 1;
568 goto warn;
bellard27503322003-11-13 01:46:15 +0000569
bellardd329a6f2004-06-07 20:58:31 +0000570 case 0xe3:
571 {
572 int i;
bellard85571bc2004-11-07 18:04:02 +0000573 for (i = sizeof (e3) - 1; i >= 0; --i)
574 dsp_out_data (s, e3[i]);
bellardd329a6f2004-06-07 20:58:31 +0000575 }
bellardd75d9f62004-10-09 17:20:54 +0000576 break;
577
bellard85571bc2004-11-07 18:04:02 +0000578 case 0xe4: /* write test reg */
579 s->needed_bytes = 1;
580 break;
581
582 case 0xe7:
583 dolog ("Attempt to probe for ESS (0xe7)?\n");
bellard1d14ffa2005-10-30 18:58:22 +0000584 break;
bellard85571bc2004-11-07 18:04:02 +0000585
bellardd75d9f62004-10-09 17:20:54 +0000586 case 0xe8: /* read test reg */
bellard85571bc2004-11-07 18:04:02 +0000587 dsp_out_data (s, s->test_reg);
bellardd75d9f62004-10-09 17:20:54 +0000588 break;
589
bellard27503322003-11-13 01:46:15 +0000590 case 0xf2:
bellard85571bc2004-11-07 18:04:02 +0000591 case 0xf3:
592 dsp_out_data (s, 0xaa);
593 s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
Jes Sorensen3a38d432009-08-14 11:36:15 +0200594 qemu_irq_raise (s->pic);
bellard85571bc2004-11-07 18:04:02 +0000595 break;
bellard27503322003-11-13 01:46:15 +0000596
bellardd75d9f62004-10-09 17:20:54 +0000597 case 0xf9:
bellard85571bc2004-11-07 18:04:02 +0000598 s->needed_bytes = 1;
599 goto warn;
bellardd75d9f62004-10-09 17:20:54 +0000600
601 case 0xfa:
bellard85571bc2004-11-07 18:04:02 +0000602 dsp_out_data (s, 0);
603 goto warn;
bellardd75d9f62004-10-09 17:20:54 +0000604
605 case 0xfc: /* FIXME */
bellard85571bc2004-11-07 18:04:02 +0000606 dsp_out_data (s, 0);
607 goto warn;
bellardd75d9f62004-10-09 17:20:54 +0000608
bellard27503322003-11-13 01:46:15 +0000609 default:
bellard1d14ffa2005-10-30 18:58:22 +0000610 dolog ("Unrecognized command %#x\n", cmd);
611 break;
bellard27503322003-11-13 01:46:15 +0000612 }
613 }
614
bellard1d14ffa2005-10-30 18:58:22 +0000615 if (!s->needed_bytes) {
bellard85571bc2004-11-07 18:04:02 +0000616 ldebug ("\n");
bellard1d14ffa2005-10-30 18:58:22 +0000617 }
618
619 exit:
620 if (!s->needed_bytes) {
621 s->cmd = -1;
622 }
623 else {
624 s->cmd = cmd;
625 }
bellard27503322003-11-13 01:46:15 +0000626 return;
bellard85571bc2004-11-07 18:04:02 +0000627
628 warn:
bellard81eea5e2005-08-21 09:30:54 +0000629 dolog ("warning: command %#x,%d is not truly understood yet\n",
bellard85571bc2004-11-07 18:04:02 +0000630 cmd, s->needed_bytes);
bellard1d14ffa2005-10-30 18:58:22 +0000631 goto exit;
632
bellard85571bc2004-11-07 18:04:02 +0000633}
634
635static uint16_t dsp_get_lohi (SB16State *s)
636{
637 uint8_t hi = dsp_get_data (s);
638 uint8_t lo = dsp_get_data (s);
639 return (hi << 8) | lo;
640}
641
642static uint16_t dsp_get_hilo (SB16State *s)
643{
644 uint8_t lo = dsp_get_data (s);
645 uint8_t hi = dsp_get_data (s);
646 return (hi << 8) | lo;
647}
648
649static void complete (SB16State *s)
650{
651 int d0, d1, d2;
652 ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
653 s->cmd, s->in_index, s->needed_bytes);
654
655 if (s->cmd > 0xaf && s->cmd < 0xd0) {
656 d2 = dsp_get_data (s);
657 d1 = dsp_get_data (s);
658 d0 = dsp_get_data (s);
659
660 if (s->cmd & 8) {
661 dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
662 s->cmd, d0, d1, d2);
663 }
664 else {
665 ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
666 s->cmd, d0, d1, d2);
667 dma_cmd (s, s->cmd, d0, d1 + (d2 << 8));
668 }
669 }
670 else {
671 switch (s->cmd) {
672 case 0x04:
673 s->csp_mode = dsp_get_data (s);
674 s->csp_reg83r = 0;
675 s->csp_reg83w = 0;
676 ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode);
677 break;
678
679 case 0x05:
680 s->csp_param = dsp_get_data (s);
681 s->csp_value = dsp_get_data (s);
682 ldebug ("CSP command 0x05: param=%#x value=%#x\n",
683 s->csp_param,
684 s->csp_value);
685 break;
686
687 case 0x0e:
688 d0 = dsp_get_data (s);
689 d1 = dsp_get_data (s);
690 ldebug ("write CSP register %d <- %#x\n", d1, d0);
691 if (d1 == 0x83) {
692 ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0);
693 s->csp_reg83[s->csp_reg83r % 4] = d0;
694 s->csp_reg83r += 1;
695 }
bellard1d14ffa2005-10-30 18:58:22 +0000696 else {
bellard85571bc2004-11-07 18:04:02 +0000697 s->csp_regs[d1] = d0;
bellard1d14ffa2005-10-30 18:58:22 +0000698 }
bellard85571bc2004-11-07 18:04:02 +0000699 break;
700
701 case 0x0f:
702 d0 = dsp_get_data (s);
703 ldebug ("read CSP register %#x -> %#x, mode=%#x\n",
704 d0, s->csp_regs[d0], s->csp_mode);
705 if (d0 == 0x83) {
706 ldebug ("0x83[%d] -> %#x\n",
707 s->csp_reg83w,
708 s->csp_reg83[s->csp_reg83w % 4]);
709 dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]);
710 s->csp_reg83w += 1;
711 }
bellard1d14ffa2005-10-30 18:58:22 +0000712 else {
bellard85571bc2004-11-07 18:04:02 +0000713 dsp_out_data (s, s->csp_regs[d0]);
bellard1d14ffa2005-10-30 18:58:22 +0000714 }
bellard85571bc2004-11-07 18:04:02 +0000715 break;
716
717 case 0x10:
718 d0 = dsp_get_data (s);
719 dolog ("cmd 0x10 d0=%#x\n", d0);
720 break;
721
722 case 0x14:
bellard15b61472004-11-14 16:02:09 +0000723 dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
bellard85571bc2004-11-07 18:04:02 +0000724 break;
725
726 case 0x40:
727 s->time_const = dsp_get_data (s);
728 ldebug ("set time const %d\n", s->time_const);
729 break;
730
731 case 0x42: /* FT2 sets output freq with this, go figure */
bellard1d14ffa2005-10-30 18:58:22 +0000732#if 0
bellard85571bc2004-11-07 18:04:02 +0000733 dolog ("cmd 0x42 might not do what it think it should\n");
bellard1d14ffa2005-10-30 18:58:22 +0000734#endif
bellard85571bc2004-11-07 18:04:02 +0000735 case 0x41:
736 s->freq = dsp_get_hilo (s);
737 ldebug ("set freq %d\n", s->freq);
738 break;
739
740 case 0x48:
bellard15b61472004-11-14 16:02:09 +0000741 s->block_size = dsp_get_lohi (s) + 1;
bellard85571bc2004-11-07 18:04:02 +0000742 ldebug ("set dma block len %d\n", s->block_size);
743 break;
744
bellard1d14ffa2005-10-30 18:58:22 +0000745 case 0x74:
746 case 0x75:
747 case 0x76:
748 case 0x77:
749 /* ADPCM stuff, ignore */
750 break;
751
bellard85571bc2004-11-07 18:04:02 +0000752 case 0x80:
753 {
bellard15b61472004-11-14 16:02:09 +0000754 int freq, samples, bytes;
bellard85571bc2004-11-07 18:04:02 +0000755 int64_t ticks;
756
bellard15b61472004-11-14 16:02:09 +0000757 freq = s->freq > 0 ? s->freq : 11025;
758 samples = dsp_get_lohi (s) + 1;
bellard85571bc2004-11-07 18:04:02 +0000759 bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
malc4f4cc0e2009-09-18 08:16:03 +0400760 ticks = muldiv64 (bytes, get_ticks_per_sec (), freq);
761 if (ticks < get_ticks_per_sec () / 1024) {
Jes Sorensen3a38d432009-08-14 11:36:15 +0200762 qemu_irq_raise (s->pic);
bellard1d14ffa2005-10-30 18:58:22 +0000763 }
764 else {
765 if (s->aux_ts) {
Alex Blighbc72ad62013-08-21 16:03:08 +0100766 timer_mod (
bellard1d14ffa2005-10-30 18:58:22 +0000767 s->aux_ts,
Alex Blighbc72ad62013-08-21 16:03:08 +0100768 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks
bellard1d14ffa2005-10-30 18:58:22 +0000769 );
770 }
771 }
bellard26a76462006-06-25 18:15:32 +0000772 ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks);
bellard85571bc2004-11-07 18:04:02 +0000773 }
774 break;
775
776 case 0xe0:
777 d0 = dsp_get_data (s);
778 s->out_data_len = 0;
779 ldebug ("E0 data = %#x\n", d0);
bellard1d14ffa2005-10-30 18:58:22 +0000780 dsp_out_data (s, ~d0);
bellard85571bc2004-11-07 18:04:02 +0000781 break;
782
783 case 0xe2:
malc514d97d2010-01-12 21:55:45 +0300784#ifdef DEBUG
bellard85571bc2004-11-07 18:04:02 +0000785 d0 = dsp_get_data (s);
malc514d97d2010-01-12 21:55:45 +0300786 dolog ("E2 = %#x\n", d0);
787#endif
bellard85571bc2004-11-07 18:04:02 +0000788 break;
789
790 case 0xe4:
791 s->test_reg = dsp_get_data (s);
792 break;
793
794 case 0xf9:
795 d0 = dsp_get_data (s);
796 ldebug ("command 0xf9 with %#x\n", d0);
797 switch (d0) {
798 case 0x0e:
799 dsp_out_data (s, 0xff);
800 break;
801
802 case 0x0f:
803 dsp_out_data (s, 0x07);
804 break;
805
806 case 0x37:
807 dsp_out_data (s, 0x38);
808 break;
809
810 default:
811 dsp_out_data (s, 0x00);
812 break;
813 }
814 break;
815
816 default:
817 dolog ("complete: unrecognized command %#x\n", s->cmd);
818 return;
819 }
820 }
821
822 ldebug ("\n");
823 s->cmd = -1;
bellard85571bc2004-11-07 18:04:02 +0000824}
825
bellardfeea13e2006-07-04 16:49:00 +0000826static void legacy_reset (SB16State *s)
827{
malc1ea879e2008-12-03 22:48:44 +0000828 struct audsettings as;
bellardfeea13e2006-07-04 16:49:00 +0000829
830 s->freq = 11025;
831 s->fmt_signed = 0;
832 s->fmt_bits = 8;
833 s->fmt_stereo = 0;
834
835 as.freq = s->freq;
836 as.nchannels = 1;
837 as.fmt = AUD_FMT_U8;
bellardd929eba2006-07-04 21:47:22 +0000838 as.endianness = 0;
bellardfeea13e2006-07-04 16:49:00 +0000839
840 s->voice = AUD_open_out (
841 &s->card,
842 s->voice,
843 "sb16",
844 s,
845 SB_audio_callback,
bellardd929eba2006-07-04 21:47:22 +0000846 &as
bellardfeea13e2006-07-04 16:49:00 +0000847 );
848
849 /* Not sure about that... */
850 /* AUD_set_active_out (s->voice, 1); */
851}
852
bellard85571bc2004-11-07 18:04:02 +0000853static void reset (SB16State *s)
854{
Jes Sorensen3a38d432009-08-14 11:36:15 +0200855 qemu_irq_lower (s->pic);
bellard85571bc2004-11-07 18:04:02 +0000856 if (s->dma_auto) {
Jes Sorensen3a38d432009-08-14 11:36:15 +0200857 qemu_irq_raise (s->pic);
858 qemu_irq_lower (s->pic);
bellard85571bc2004-11-07 18:04:02 +0000859 }
860
861 s->mixer_regs[0x82] = 0;
862 s->dma_auto = 0;
863 s->in_index = 0;
864 s->out_data_len = 0;
865 s->left_till_irq = 0;
866 s->needed_bytes = 0;
867 s->block_size = -1;
868 s->nzero = 0;
869 s->highspeed = 0;
870 s->v2x6 = 0;
bellard1d14ffa2005-10-30 18:58:22 +0000871 s->cmd = -1;
bellard85571bc2004-11-07 18:04:02 +0000872
malc31226162009-09-10 19:59:50 +0400873 dsp_out_data (s, 0xaa);
bellard85571bc2004-11-07 18:04:02 +0000874 speaker (s, 0);
875 control (s, 0);
bellardfeea13e2006-07-04 16:49:00 +0000876 legacy_reset (s);
bellard27503322003-11-13 01:46:15 +0000877}
878
Nutan Shinde8307c292015-10-07 22:02:54 +0530879static void dsp_write(void *opaque, uint32_t nport, uint32_t val)
bellard27503322003-11-13 01:46:15 +0000880{
bellard85571bc2004-11-07 18:04:02 +0000881 SB16State *s = opaque;
bellard27503322003-11-13 01:46:15 +0000882 int iport;
883
bellard85571bc2004-11-07 18:04:02 +0000884 iport = nport - s->port;
bellard27503322003-11-13 01:46:15 +0000885
bellard85571bc2004-11-07 18:04:02 +0000886 ldebug ("write %#x <- %#x\n", nport, val);
bellard27503322003-11-13 01:46:15 +0000887 switch (iport) {
bellard85571bc2004-11-07 18:04:02 +0000888 case 0x06:
889 switch (val) {
890 case 0x00:
891 if (s->v2x6 == 1) {
malccd7aafc2009-11-18 19:17:03 +0300892 reset (s);
bellard85571bc2004-11-07 18:04:02 +0000893 }
894 s->v2x6 = 0;
895 break;
896
897 case 0x01:
898 case 0x03: /* FreeBSD kludge */
899 s->v2x6 = 1;
900 break;
901
902 case 0xc6:
903 s->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */
904 break;
905
906 case 0xb8: /* Panic */
907 reset (s);
908 break;
909
910 case 0x39:
911 dsp_out_data (s, 0x38);
912 reset (s);
913 s->v2x6 = 0x39;
914 break;
915
916 default:
917 s->v2x6 = val;
918 break;
bellard27503322003-11-13 01:46:15 +0000919 }
bellard27503322003-11-13 01:46:15 +0000920 break;
921
bellard85571bc2004-11-07 18:04:02 +0000922 case 0x0c: /* write data or command | write status */
923/* if (s->highspeed) */
924/* break; */
925
Gonglei2ab5bf62014-08-11 21:00:53 +0800926 if (s->needed_bytes == 0) {
bellard85571bc2004-11-07 18:04:02 +0000927 command (s, val);
928#if 0
929 if (0 == s->needed_bytes) {
930 log_dsp (s);
bellard27503322003-11-13 01:46:15 +0000931 }
bellard85571bc2004-11-07 18:04:02 +0000932#endif
bellard27503322003-11-13 01:46:15 +0000933 }
934 else {
bellard85571bc2004-11-07 18:04:02 +0000935 if (s->in_index == sizeof (s->in2_data)) {
bellardd75d9f62004-10-09 17:20:54 +0000936 dolog ("in data overrun\n");
937 }
938 else {
bellard85571bc2004-11-07 18:04:02 +0000939 s->in2_data[s->in_index++] = val;
940 if (s->in_index == s->needed_bytes) {
941 s->needed_bytes = 0;
942 complete (s);
943#if 0
944 log_dsp (s);
945#endif
946 }
bellard27503322003-11-13 01:46:15 +0000947 }
948 }
949 break;
950
951 default:
bellard85571bc2004-11-07 18:04:02 +0000952 ldebug ("(nport=%#x, val=%#x)\n", nport, val);
bellard5e2a6442004-03-23 22:42:11 +0000953 break;
bellard27503322003-11-13 01:46:15 +0000954 }
955}
956
Nutan Shinde8307c292015-10-07 22:02:54 +0530957static uint32_t dsp_read(void *opaque, uint32_t nport)
bellard27503322003-11-13 01:46:15 +0000958{
bellard85571bc2004-11-07 18:04:02 +0000959 SB16State *s = opaque;
960 int iport, retval, ack = 0;
bellard27503322003-11-13 01:46:15 +0000961
bellard85571bc2004-11-07 18:04:02 +0000962 iport = nport - s->port;
bellard27503322003-11-13 01:46:15 +0000963
964 switch (iport) {
bellard85571bc2004-11-07 18:04:02 +0000965 case 0x06: /* reset */
966 retval = 0xff;
bellardd75d9f62004-10-09 17:20:54 +0000967 break;
bellard27503322003-11-13 01:46:15 +0000968
bellard85571bc2004-11-07 18:04:02 +0000969 case 0x0a: /* read data */
970 if (s->out_data_len) {
971 retval = s->out_data[--s->out_data_len];
972 s->last_read_byte = retval;
973 }
974 else {
bellard1d14ffa2005-10-30 18:58:22 +0000975 if (s->cmd != -1) {
976 dolog ("empty output buffer for command %#x\n",
977 s->cmd);
978 }
bellard85571bc2004-11-07 18:04:02 +0000979 retval = s->last_read_byte;
bellardd75d9f62004-10-09 17:20:54 +0000980 /* goto error; */
bellard27503322003-11-13 01:46:15 +0000981 }
982 break;
983
bellard85571bc2004-11-07 18:04:02 +0000984 case 0x0c: /* 0 can write */
985 retval = s->can_write ? 0 : 0x80;
986 break;
987
988 case 0x0d: /* timer interrupt clear */
989 /* dolog ("timer interrupt clear\n"); */
bellard27503322003-11-13 01:46:15 +0000990 retval = 0;
991 break;
992
bellard85571bc2004-11-07 18:04:02 +0000993 case 0x0e: /* data available status | irq 8 ack */
994 retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
995 if (s->mixer_regs[0x82] & 1) {
996 ack = 1;
Paolo Bonzini99393752015-01-20 17:23:48 +0100997 s->mixer_regs[0x82] &= ~1;
Jes Sorensen3a38d432009-08-14 11:36:15 +0200998 qemu_irq_lower (s->pic);
bellard85571bc2004-11-07 18:04:02 +0000999 }
bellard27503322003-11-13 01:46:15 +00001000 break;
1001
bellard85571bc2004-11-07 18:04:02 +00001002 case 0x0f: /* irq 16 ack */
bellardbc0b1dc2004-01-18 22:19:31 +00001003 retval = 0xff;
bellard85571bc2004-11-07 18:04:02 +00001004 if (s->mixer_regs[0x82] & 2) {
1005 ack = 1;
Paolo Bonzini99393752015-01-20 17:23:48 +01001006 s->mixer_regs[0x82] &= ~2;
Jes Sorensen3a38d432009-08-14 11:36:15 +02001007 qemu_irq_lower (s->pic);
bellard85571bc2004-11-07 18:04:02 +00001008 }
bellard27503322003-11-13 01:46:15 +00001009 break;
1010
1011 default:
1012 goto error;
1013 }
1014
bellard1d14ffa2005-10-30 18:58:22 +00001015 if (!ack) {
bellard85571bc2004-11-07 18:04:02 +00001016 ldebug ("read %#x -> %#x\n", nport, retval);
bellard1d14ffa2005-10-30 18:58:22 +00001017 }
bellard27503322003-11-13 01:46:15 +00001018
1019 return retval;
1020
1021 error:
bellard1d14ffa2005-10-30 18:58:22 +00001022 dolog ("warning: dsp_read %#x error\n", nport);
bellardd75d9f62004-10-09 17:20:54 +00001023 return 0xff;
bellard27503322003-11-13 01:46:15 +00001024}
1025
bellard85571bc2004-11-07 18:04:02 +00001026static void reset_mixer (SB16State *s)
1027{
1028 int i;
1029
1030 memset (s->mixer_regs, 0xff, 0x7f);
1031 memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83);
1032
1033 s->mixer_regs[0x02] = 4; /* master volume 3bits */
1034 s->mixer_regs[0x06] = 4; /* MIDI volume 3bits */
1035 s->mixer_regs[0x08] = 0; /* CD volume 3bits */
1036 s->mixer_regs[0x0a] = 0; /* voice volume 2bits */
1037
1038 /* d5=input filt, d3=lowpass filt, d1,d2=input source */
1039 s->mixer_regs[0x0c] = 0;
1040
1041 /* d5=output filt, d1=stereo switch */
1042 s->mixer_regs[0x0e] = 0;
1043
1044 /* voice volume L d5,d7, R d1,d3 */
1045 s->mixer_regs[0x04] = (4 << 5) | (4 << 1);
1046 /* master ... */
1047 s->mixer_regs[0x22] = (4 << 5) | (4 << 1);
1048 /* MIDI ... */
1049 s->mixer_regs[0x26] = (4 << 5) | (4 << 1);
1050
1051 for (i = 0x30; i < 0x48; i++) {
1052 s->mixer_regs[i] = 0x20;
1053 }
1054}
1055
Nutan Shinde8307c292015-10-07 22:02:54 +05301056static void mixer_write_indexb(void *opaque, uint32_t nport, uint32_t val)
bellard27503322003-11-13 01:46:15 +00001057{
bellard85571bc2004-11-07 18:04:02 +00001058 SB16State *s = opaque;
bellardc0fe3822005-11-05 18:55:28 +00001059 (void) nport;
bellard85571bc2004-11-07 18:04:02 +00001060 s->mixer_nreg = val;
bellard27503322003-11-13 01:46:15 +00001061}
1062
Nutan Shinde8307c292015-10-07 22:02:54 +05301063static void mixer_write_datab(void *opaque, uint32_t nport, uint32_t val)
bellard27503322003-11-13 01:46:15 +00001064{
bellard85571bc2004-11-07 18:04:02 +00001065 SB16State *s = opaque;
bellard202a4562004-04-16 22:09:02 +00001066
bellardc0fe3822005-11-05 18:55:28 +00001067 (void) nport;
bellard85571bc2004-11-07 18:04:02 +00001068 ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
bellard85571bc2004-11-07 18:04:02 +00001069
1070 switch (s->mixer_nreg) {
bellardd75d9f62004-10-09 17:20:54 +00001071 case 0x00:
bellard85571bc2004-11-07 18:04:02 +00001072 reset_mixer (s);
1073 break;
bellardd75d9f62004-10-09 17:20:54 +00001074
bellard85571bc2004-11-07 18:04:02 +00001075 case 0x80:
1076 {
1077 int irq = irq_of_magic (val);
1078 ldebug ("setting irq to %d (val=%#x)\n", irq, val);
bellard1d14ffa2005-10-30 18:58:22 +00001079 if (irq > 0) {
bellard85571bc2004-11-07 18:04:02 +00001080 s->irq = irq;
bellard1d14ffa2005-10-30 18:58:22 +00001081 }
bellardd75d9f62004-10-09 17:20:54 +00001082 }
1083 break;
1084
bellardd75d9f62004-10-09 17:20:54 +00001085 case 0x81:
bellard85571bc2004-11-07 18:04:02 +00001086 {
1087 int dma, hdma;
1088
malc057fa652009-09-12 02:39:29 +04001089 dma = ctz32 (val & 0xf);
1090 hdma = ctz32 (val & 0xf0);
bellard1d14ffa2005-10-30 18:58:22 +00001091 if (dma != s->dma || hdma != s->hdma) {
1092 dolog (
1093 "attempt to change DMA "
1094 "8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
1095 dma, s->dma, hdma, s->hdma, val);
1096 }
bellard85571bc2004-11-07 18:04:02 +00001097#if 0
1098 s->dma = dma;
1099 s->hdma = hdma;
1100#endif
1101 }
bellardd75d9f62004-10-09 17:20:54 +00001102 break;
bellard85571bc2004-11-07 18:04:02 +00001103
1104 case 0x82:
1105 dolog ("attempt to write into IRQ status register (val=%#x)\n",
1106 val);
bellard202a4562004-04-16 22:09:02 +00001107 return;
bellard85571bc2004-11-07 18:04:02 +00001108
1109 default:
bellard1d14ffa2005-10-30 18:58:22 +00001110 if (s->mixer_nreg >= 0x80) {
1111 ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
1112 }
bellard85571bc2004-11-07 18:04:02 +00001113 break;
bellardd75d9f62004-10-09 17:20:54 +00001114 }
bellard27503322003-11-13 01:46:15 +00001115
bellard85571bc2004-11-07 18:04:02 +00001116 s->mixer_regs[s->mixer_nreg] = val;
bellardd75d9f62004-10-09 17:20:54 +00001117}
1118
Nutan Shinde8307c292015-10-07 22:02:54 +05301119static uint32_t mixer_read(void *opaque, uint32_t nport)
bellard27503322003-11-13 01:46:15 +00001120{
bellard85571bc2004-11-07 18:04:02 +00001121 SB16State *s = opaque;
bellardc0fe3822005-11-05 18:55:28 +00001122
1123 (void) nport;
bellard15b61472004-11-14 16:02:09 +00001124#ifndef DEBUG_SB16_MOST
bellard1d14ffa2005-10-30 18:58:22 +00001125 if (s->mixer_nreg != 0x82) {
1126 ldebug ("mixer_read[%#x] -> %#x\n",
1127 s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
1128 }
1129#else
bellard85571bc2004-11-07 18:04:02 +00001130 ldebug ("mixer_read[%#x] -> %#x\n",
1131 s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
bellard1d14ffa2005-10-30 18:58:22 +00001132#endif
bellard85571bc2004-11-07 18:04:02 +00001133 return s->mixer_regs[s->mixer_nreg];
bellard27503322003-11-13 01:46:15 +00001134}
1135
bellard85571bc2004-11-07 18:04:02 +00001136static int write_audio (SB16State *s, int nchan, int dma_pos,
1137 int dma_len, int len)
bellard27503322003-11-13 01:46:15 +00001138{
1139 int temp, net;
bellardf9e92e92004-02-25 23:32:01 +00001140 uint8_t tmpbuf[4096];
bellard27503322003-11-13 01:46:15 +00001141
bellard85571bc2004-11-07 18:04:02 +00001142 temp = len;
bellard27503322003-11-13 01:46:15 +00001143 net = 0;
1144
1145 while (temp) {
bellard85571bc2004-11-07 18:04:02 +00001146 int left = dma_len - dma_pos;
bellardc0fe3822005-11-05 18:55:28 +00001147 int copied;
1148 size_t to_copy;
bellard27503322003-11-13 01:46:15 +00001149
bellard85571bc2004-11-07 18:04:02 +00001150 to_copy = audio_MIN (temp, left);
bellardc0fe3822005-11-05 18:55:28 +00001151 if (to_copy > sizeof (tmpbuf)) {
1152 to_copy = sizeof (tmpbuf);
bellard1d14ffa2005-10-30 18:58:22 +00001153 }
bellard85571bc2004-11-07 18:04:02 +00001154
1155 copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
1156 copied = AUD_write (s->voice, tmpbuf, copied);
bellard27503322003-11-13 01:46:15 +00001157
1158 temp -= copied;
bellard85571bc2004-11-07 18:04:02 +00001159 dma_pos = (dma_pos + copied) % dma_len;
bellard27503322003-11-13 01:46:15 +00001160 net += copied;
1161
bellard1d14ffa2005-10-30 18:58:22 +00001162 if (!copied) {
bellard85571bc2004-11-07 18:04:02 +00001163 break;
bellard1d14ffa2005-10-30 18:58:22 +00001164 }
bellard27503322003-11-13 01:46:15 +00001165 }
1166
1167 return net;
1168}
1169
bellard85571bc2004-11-07 18:04:02 +00001170static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
bellard27503322003-11-13 01:46:15 +00001171{
bellard85571bc2004-11-07 18:04:02 +00001172 SB16State *s = opaque;
bellard1d14ffa2005-10-30 18:58:22 +00001173 int till, copy, written, free;
bellard27503322003-11-13 01:46:15 +00001174
balrogca9cc282008-01-14 04:24:29 +00001175 if (s->block_size <= 0) {
1176 dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
1177 s->block_size, nchan, dma_pos, dma_len);
1178 return dma_pos;
1179 }
1180
bellard85571bc2004-11-07 18:04:02 +00001181 if (s->left_till_irq < 0) {
1182 s->left_till_irq = s->block_size;
bellard27503322003-11-13 01:46:15 +00001183 }
1184
bellard1d14ffa2005-10-30 18:58:22 +00001185 if (s->voice) {
1186 free = s->audio_free & ~s->align;
1187 if ((free <= 0) || !dma_len) {
1188 return dma_pos;
1189 }
1190 }
1191 else {
1192 free = dma_len;
bellard27503322003-11-13 01:46:15 +00001193 }
1194
bellard85571bc2004-11-07 18:04:02 +00001195 copy = free;
1196 till = s->left_till_irq;
bellard27503322003-11-13 01:46:15 +00001197
bellardd75d9f62004-10-09 17:20:54 +00001198#ifdef DEBUG_SB16_MOST
bellard1d14ffa2005-10-30 18:58:22 +00001199 dolog ("pos:%06d %d till:%d len:%d\n",
1200 dma_pos, free, till, dma_len);
bellardd75d9f62004-10-09 17:20:54 +00001201#endif
1202
bellard27503322003-11-13 01:46:15 +00001203 if (till <= copy) {
Gonglei2ab5bf62014-08-11 21:00:53 +08001204 if (s->dma_auto == 0) {
bellard27503322003-11-13 01:46:15 +00001205 copy = till;
1206 }
1207 }
1208
bellard85571bc2004-11-07 18:04:02 +00001209 written = write_audio (s, nchan, dma_pos, dma_len, copy);
1210 dma_pos = (dma_pos + written) % dma_len;
1211 s->left_till_irq -= written;
bellard27503322003-11-13 01:46:15 +00001212
bellard85571bc2004-11-07 18:04:02 +00001213 if (s->left_till_irq <= 0) {
1214 s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
Jes Sorensen3a38d432009-08-14 11:36:15 +02001215 qemu_irq_raise (s->pic);
Gonglei2ab5bf62014-08-11 21:00:53 +08001216 if (s->dma_auto == 0) {
bellard85571bc2004-11-07 18:04:02 +00001217 control (s, 0);
1218 speaker (s, 0);
bellard27503322003-11-13 01:46:15 +00001219 }
1220 }
1221
bellardd75d9f62004-10-09 17:20:54 +00001222#ifdef DEBUG_SB16_MOST
bellard15b61472004-11-14 16:02:09 +00001223 ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
1224 dma_pos, free, dma_len, s->left_till_irq, copy, written,
1225 s->block_size);
bellardd75d9f62004-10-09 17:20:54 +00001226#endif
bellard27503322003-11-13 01:46:15 +00001227
bellard85571bc2004-11-07 18:04:02 +00001228 while (s->left_till_irq <= 0) {
1229 s->left_till_irq = s->block_size + s->left_till_irq;
bellard27503322003-11-13 01:46:15 +00001230 }
1231
bellard85571bc2004-11-07 18:04:02 +00001232 return dma_pos;
bellard27503322003-11-13 01:46:15 +00001233}
1234
bellard1d14ffa2005-10-30 18:58:22 +00001235static void SB_audio_callback (void *opaque, int free)
bellard27503322003-11-13 01:46:15 +00001236{
bellard85571bc2004-11-07 18:04:02 +00001237 SB16State *s = opaque;
bellard1d14ffa2005-10-30 18:58:22 +00001238 s->audio_free = free;
bellard27503322003-11-13 01:46:15 +00001239}
1240
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001241static int sb16_post_load (void *opaque, int version_id)
bellard27503322003-11-13 01:46:15 +00001242{
bellard85571bc2004-11-07 18:04:02 +00001243 SB16State *s = opaque;
bellard27503322003-11-13 01:46:15 +00001244
bellardfb065182004-11-09 23:09:44 +00001245 if (s->voice) {
bellardc0fe3822005-11-05 18:55:28 +00001246 AUD_close_out (&s->card, s->voice);
bellardfb065182004-11-09 23:09:44 +00001247 s->voice = NULL;
1248 }
bellard85571bc2004-11-07 18:04:02 +00001249
1250 if (s->dma_running) {
bellard1d14ffa2005-10-30 18:58:22 +00001251 if (s->freq) {
malc1ea879e2008-12-03 22:48:44 +00001252 struct audsettings as;
bellardc0fe3822005-11-05 18:55:28 +00001253
bellard1d14ffa2005-10-30 18:58:22 +00001254 s->audio_free = 0;
bellardc0fe3822005-11-05 18:55:28 +00001255
1256 as.freq = s->freq;
1257 as.nchannels = 1 << s->fmt_stereo;
1258 as.fmt = s->fmt;
bellardd929eba2006-07-04 21:47:22 +00001259 as.endianness = 0;
bellardc0fe3822005-11-05 18:55:28 +00001260
bellard1d14ffa2005-10-30 18:58:22 +00001261 s->voice = AUD_open_out (
bellardc0fe3822005-11-05 18:55:28 +00001262 &s->card,
bellard1d14ffa2005-10-30 18:58:22 +00001263 s->voice,
1264 "sb16",
1265 s,
1266 SB_audio_callback,
bellardd929eba2006-07-04 21:47:22 +00001267 &as
bellard1d14ffa2005-10-30 18:58:22 +00001268 );
1269 }
bellard85571bc2004-11-07 18:04:02 +00001270
1271 control (s, 1);
1272 speaker (s, s->speaker);
bellardd75d9f62004-10-09 17:20:54 +00001273 }
bellard85571bc2004-11-07 18:04:02 +00001274 return 0;
bellardd75d9f62004-10-09 17:20:54 +00001275}
bellardd75d9f62004-10-09 17:20:54 +00001276
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001277static const VMStateDescription vmstate_sb16 = {
1278 .name = "sb16",
1279 .version_id = 1,
1280 .minimum_version_id = 1,
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001281 .post_load = sb16_post_load,
Juan Quintelad49805a2014-04-16 15:32:32 +02001282 .fields = (VMStateField[]) {
malccf4dc462012-02-07 22:11:04 +04001283 VMSTATE_UINT32 (irq, SB16State),
1284 VMSTATE_UINT32 (dma, SB16State),
1285 VMSTATE_UINT32 (hdma, SB16State),
1286 VMSTATE_UINT32 (port, SB16State),
1287 VMSTATE_UINT32 (ver, SB16State),
1288 VMSTATE_INT32 (in_index, SB16State),
1289 VMSTATE_INT32 (out_data_len, SB16State),
1290 VMSTATE_INT32 (fmt_stereo, SB16State),
1291 VMSTATE_INT32 (fmt_signed, SB16State),
1292 VMSTATE_INT32 (fmt_bits, SB16State),
1293 VMSTATE_UINT32 (fmt, SB16State),
1294 VMSTATE_INT32 (dma_auto, SB16State),
1295 VMSTATE_INT32 (block_size, SB16State),
1296 VMSTATE_INT32 (fifo, SB16State),
1297 VMSTATE_INT32 (freq, SB16State),
1298 VMSTATE_INT32 (time_const, SB16State),
1299 VMSTATE_INT32 (speaker, SB16State),
1300 VMSTATE_INT32 (needed_bytes, SB16State),
1301 VMSTATE_INT32 (cmd, SB16State),
1302 VMSTATE_INT32 (use_hdma, SB16State),
1303 VMSTATE_INT32 (highspeed, SB16State),
1304 VMSTATE_INT32 (can_write, SB16State),
1305 VMSTATE_INT32 (v2x6, SB16State),
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001306
malccf4dc462012-02-07 22:11:04 +04001307 VMSTATE_UINT8 (csp_param, SB16State),
1308 VMSTATE_UINT8 (csp_value, SB16State),
1309 VMSTATE_UINT8 (csp_mode, SB16State),
1310 VMSTATE_UINT8 (csp_param, SB16State),
1311 VMSTATE_BUFFER (csp_regs, SB16State),
1312 VMSTATE_UINT8 (csp_index, SB16State),
1313 VMSTATE_BUFFER (csp_reg83, SB16State),
1314 VMSTATE_INT32 (csp_reg83r, SB16State),
1315 VMSTATE_INT32 (csp_reg83w, SB16State),
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001316
malccf4dc462012-02-07 22:11:04 +04001317 VMSTATE_BUFFER (in2_data, SB16State),
1318 VMSTATE_BUFFER (out_data, SB16State),
1319 VMSTATE_UINT8 (test_reg, SB16State),
1320 VMSTATE_UINT8 (last_read_byte, SB16State),
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001321
malccf4dc462012-02-07 22:11:04 +04001322 VMSTATE_INT32 (nzero, SB16State),
1323 VMSTATE_INT32 (left_till_irq, SB16State),
1324 VMSTATE_INT32 (dma_running, SB16State),
1325 VMSTATE_INT32 (bytes_per_second, SB16State),
1326 VMSTATE_INT32 (align, SB16State),
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001327
malccf4dc462012-02-07 22:11:04 +04001328 VMSTATE_INT32 (mixer_nreg, SB16State),
1329 VMSTATE_BUFFER (mixer_regs, SB16State),
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001330
malccf4dc462012-02-07 22:11:04 +04001331 VMSTATE_END_OF_LIST ()
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001332 }
1333};
1334
Richard Henderson42c1a222011-08-15 16:10:47 -07001335static const MemoryRegionPortio sb16_ioport_list[] = {
1336 { 4, 1, 1, .write = mixer_write_indexb },
Richard Henderson42c1a222011-08-15 16:10:47 -07001337 { 5, 1, 1, .read = mixer_read, .write = mixer_write_datab },
1338 { 6, 1, 1, .read = dsp_read, .write = dsp_write },
1339 { 10, 1, 1, .read = dsp_read },
1340 { 12, 1, 1, .write = dsp_write },
1341 { 12, 4, 1, .read = dsp_read },
malccf4dc462012-02-07 22:11:04 +04001342 PORTIO_END_OF_LIST (),
Richard Henderson42c1a222011-08-15 16:10:47 -07001343};
1344
1345
Andreas Färberdb895a12012-11-25 02:37:14 +01001346static void sb16_initfn (Object *obj)
bellard27503322003-11-13 01:46:15 +00001347{
Andreas Färberdb895a12012-11-25 02:37:14 +01001348 SB16State *s = SB16 (obj);
bellardc0fe3822005-11-05 18:55:28 +00001349
bellard1d14ffa2005-10-30 18:58:22 +00001350 s->cmd = -1;
Andreas Färberdb895a12012-11-25 02:37:14 +01001351}
1352
1353static void sb16_realizefn (DeviceState *dev, Error **errp)
1354{
1355 ISADevice *isadev = ISA_DEVICE (dev);
1356 SB16State *s = SB16 (dev);
1357
1358 isa_init_irq (isadev, &s->pic, s->irq);
bellard27503322003-11-13 01:46:15 +00001359
bellard85571bc2004-11-07 18:04:02 +00001360 s->mixer_regs[0x80] = magic_of_irq (s->irq);
1361 s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
1362 s->mixer_regs[0x82] = 2 << 5;
1363
1364 s->csp_regs[5] = 1;
1365 s->csp_regs[9] = 0xf8;
1366
1367 reset_mixer (s);
Alex Blighbc72ad62013-08-21 16:03:08 +01001368 s->aux_ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, aux_timer, s);
bellard1d14ffa2005-10-30 18:58:22 +00001369 if (!s->aux_ts) {
bellardc0fe3822005-11-05 18:55:28 +00001370 dolog ("warning: Could not create auxiliary timer\n");
bellard1d14ffa2005-10-30 18:58:22 +00001371 }
bellard27503322003-11-13 01:46:15 +00001372
Andreas Färberdb895a12012-11-25 02:37:14 +01001373 isa_register_portio_list (isadev, s->port, sb16_ioport_list, s, "sb16");
bellard85571bc2004-11-07 18:04:02 +00001374
1375 DMA_register_channel (s->hdma, SB_read_DMA, s);
1376 DMA_register_channel (s->dma, SB_read_DMA, s);
1377 s->can_write = 1;
1378
malc1a7dafc2009-05-14 03:11:35 +04001379 AUD_register_card ("sb16", &s->card);
bellard27503322003-11-13 01:46:15 +00001380}
Gerd Hoffmannf7b4f612009-09-10 11:43:30 +02001381
Paolo Bonzini36cd6f62013-04-18 18:43:58 +02001382static int SB16_init (ISABus *bus)
Gerd Hoffmannf7b4f612009-09-10 11:43:30 +02001383{
Andreas Färber399f05a2013-04-27 22:18:49 +02001384 isa_create_simple (bus, TYPE_SB16);
Gerd Hoffmannf7b4f612009-09-10 11:43:30 +02001385 return 0;
1386}
1387
Anthony Liguori39bffca2011-12-07 21:34:16 -06001388static Property sb16_properties[] = {
Paolo Bonzinic7bcc852014-02-08 11:01:53 +01001389 DEFINE_PROP_UINT32 ("version", SB16State, ver, 0x0405), /* 4.5 */
1390 DEFINE_PROP_UINT32 ("iobase", SB16State, port, 0x220),
Anthony Liguori39bffca2011-12-07 21:34:16 -06001391 DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5),
1392 DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1),
1393 DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5),
1394 DEFINE_PROP_END_OF_LIST (),
1395};
1396
malccf4dc462012-02-07 22:11:04 +04001397static void sb16_class_initfn (ObjectClass *klass, void *data)
Anthony Liguori8f04ee02011-12-04 11:52:49 -06001398{
malccf4dc462012-02-07 22:11:04 +04001399 DeviceClass *dc = DEVICE_CLASS (klass);
Andreas Färberdb895a12012-11-25 02:37:14 +01001400
1401 dc->realize = sb16_realizefn;
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +03001402 set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
Anthony Liguori39bffca2011-12-07 21:34:16 -06001403 dc->desc = "Creative Sound Blaster 16";
1404 dc->vmsd = &vmstate_sb16;
1405 dc->props = sb16_properties;
Anthony Liguori8f04ee02011-12-04 11:52:49 -06001406}
1407
Andreas Färber8c43a6f2013-01-10 16:19:07 +01001408static const TypeInfo sb16_info = {
Andreas Färber399f05a2013-04-27 22:18:49 +02001409 .name = TYPE_SB16,
Anthony Liguori39bffca2011-12-07 21:34:16 -06001410 .parent = TYPE_ISA_DEVICE,
1411 .instance_size = sizeof (SB16State),
Andreas Färberdb895a12012-11-25 02:37:14 +01001412 .instance_init = sb16_initfn,
Anthony Liguori39bffca2011-12-07 21:34:16 -06001413 .class_init = sb16_class_initfn,
Gerd Hoffmannf7b4f612009-09-10 11:43:30 +02001414};
1415
Andreas Färber83f7d432012-02-09 15:20:55 +01001416static void sb16_register_types (void)
Gerd Hoffmannf7b4f612009-09-10 11:43:30 +02001417{
malccf4dc462012-02-07 22:11:04 +04001418 type_register_static (&sb16_info);
Paolo Bonzini36cd6f62013-04-18 18:43:58 +02001419 isa_register_soundhw("sb16", "Creative Sound Blaster 16", SB16_init);
Gerd Hoffmannf7b4f612009-09-10 11:43:30 +02001420}
Andreas Färber83f7d432012-02-09 15:20:55 +01001421
1422type_init (sb16_register_types)