blob: fd76e78d180ce7c5845ff989e355083088d8d760 [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 */
Markus Armbruster0b8fa322019-05-23 16:35:07 +020024
Peter Maydell6086a562016-01-18 17:33:52 +000025#include "qemu/osdep.h"
Eduardo Habkost8a824e42017-05-08 17:57:35 -030026#include "hw/audio/soundhw.h"
pbrook87ecb682007-11-17 17:14:51 +000027#include "audio/audio.h"
Markus Armbruster64552b62019-08-12 07:23:42 +020028#include "hw/irq.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010029#include "hw/isa/isa.h"
Markus Armbrustera27bd6c2019-08-12 07:23:51 +020030#include "hw/qdev-properties.h"
Markus Armbrusterd6454272019-08-12 07:23:45 +020031#include "migration/vmstate.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010032#include "qemu/timer.h"
33#include "qemu/host-utils.h"
John Arbuckle8ec660b2018-02-01 12:27:44 -050034#include "qemu/log.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020035#include "qemu/module.h"
John Arbuckle8ec660b2018-02-01 12:27:44 -050036#include "qapi/error.h"
Eduardo Habkostdb1015e2020-09-03 16:43:22 -040037#include "qom/object.h"
bellard27503322003-11-13 01:46:15 +000038
bellardfb065182004-11-09 23:09:44 +000039#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
bellard15b61472004-11-14 16:02:09 +000040
41/* #define DEBUG */
42/* #define DEBUG_SB16_MOST */
43
bellardfb065182004-11-09 23:09:44 +000044#ifdef DEBUG
45#define ldebug(...) dolog (__VA_ARGS__)
46#else
47#define ldebug(...)
48#endif
49
bellard85571bc2004-11-07 18:04:02 +000050static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
bellardd329a6f2004-06-07 20:58:31 +000051
Andreas Färber399f05a2013-04-27 22:18:49 +020052#define TYPE_SB16 "sb16"
Eduardo Habkost80633962020-09-16 14:25:19 -040053OBJECT_DECLARE_SIMPLE_TYPE(SB16State, SB16)
Andreas Färber399f05a2013-04-27 22:18:49 +020054
Eduardo Habkostdb1015e2020-09-03 16:43:22 -040055struct SB16State {
Andreas Färber399f05a2013-04-27 22:18:49 +020056 ISADevice parent_obj;
57
bellardc0fe3822005-11-05 18:55:28 +000058 QEMUSoundCard card;
Jes Sorensen3a38d432009-08-14 11:36:15 +020059 qemu_irq pic;
Gerd Hoffmannf7b4f612009-09-10 11:43:30 +020060 uint32_t irq;
61 uint32_t dma;
62 uint32_t hdma;
63 uint32_t port;
64 uint32_t ver;
Hervé Poussineauf203c162016-02-03 11:28:58 -050065 IsaDma *isa_dma;
66 IsaDma *isa_hdma;
bellard85571bc2004-11-07 18:04:02 +000067
bellard27503322003-11-13 01:46:15 +000068 int in_index;
69 int out_data_len;
70 int fmt_stereo;
71 int fmt_signed;
72 int fmt_bits;
Kővágó, Zoltán85bc5852019-03-08 23:34:13 +010073 AudioFormat fmt;
bellard27503322003-11-13 01:46:15 +000074 int dma_auto;
bellard85571bc2004-11-07 18:04:02 +000075 int block_size;
bellard27503322003-11-13 01:46:15 +000076 int fifo;
77 int freq;
78 int time_const;
79 int speaker;
80 int needed_bytes;
81 int cmd;
bellard27503322003-11-13 01:46:15 +000082 int use_hdma;
bellard85571bc2004-11-07 18:04:02 +000083 int highspeed;
84 int can_write;
bellard27503322003-11-13 01:46:15 +000085
86 int v2x6;
87
bellard85571bc2004-11-07 18:04:02 +000088 uint8_t csp_param;
89 uint8_t csp_value;
90 uint8_t csp_mode;
91 uint8_t csp_regs[256];
92 uint8_t csp_index;
93 uint8_t csp_reg83[4];
94 int csp_reg83r;
95 int csp_reg83w;
96
bellardd75d9f62004-10-09 17:20:54 +000097 uint8_t in2_data[10];
bellard85571bc2004-11-07 18:04:02 +000098 uint8_t out_data[50];
99 uint8_t test_reg;
100 uint8_t last_read_byte;
101 int nzero;
bellard27503322003-11-13 01:46:15 +0000102
103 int left_till_irq;
bellard27503322003-11-13 01:46:15 +0000104
bellard85571bc2004-11-07 18:04:02 +0000105 int dma_running;
106 int bytes_per_second;
107 int align;
bellard1d14ffa2005-10-30 18:58:22 +0000108 int audio_free;
109 SWVoiceOut *voice;
bellard85571bc2004-11-07 18:04:02 +0000110
bellard1d14ffa2005-10-30 18:58:22 +0000111 QEMUTimer *aux_ts;
bellard5e2a6442004-03-23 22:42:11 +0000112 /* mixer state */
113 int mixer_nreg;
bellard202a4562004-04-16 22:09:02 +0000114 uint8_t mixer_regs[256];
Marc-André Lureaue305a162016-07-13 02:11:59 +0200115 PortioList portio_list;
Eduardo Habkostdb1015e2020-09-03 16:43:22 -0400116};
bellard27503322003-11-13 01:46:15 +0000117
Philippe Mathieu-Daudéa2cd86a2021-06-16 12:43:49 +0200118#define SAMPLE_RATE_MIN 5000
119#define SAMPLE_RATE_MAX 45000
120
bellard1d14ffa2005-10-30 18:58:22 +0000121static void SB_audio_callback (void *opaque, int free);
122
bellard85571bc2004-11-07 18:04:02 +0000123static int magic_of_irq (int irq)
124{
125 switch (irq) {
126 case 5:
127 return 2;
128 case 7:
129 return 4;
130 case 9:
131 return 1;
132 case 10:
133 return 8;
134 default:
John Arbuckle8ec660b2018-02-01 12:27:44 -0500135 qemu_log_mask(LOG_GUEST_ERROR, "bad irq %d\n", irq);
bellard85571bc2004-11-07 18:04:02 +0000136 return 2;
137 }
138}
139
140static int irq_of_magic (int magic)
141{
142 switch (magic) {
143 case 1:
144 return 9;
145 case 2:
146 return 5;
147 case 4:
148 return 7;
149 case 8:
150 return 10;
151 default:
John Arbuckle8ec660b2018-02-01 12:27:44 -0500152 qemu_log_mask(LOG_GUEST_ERROR, "bad irq magic %d\n", magic);
bellard85571bc2004-11-07 18:04:02 +0000153 return -1;
154 }
155}
156
157#if 0
bellard5e2a6442004-03-23 22:42:11 +0000158static void log_dsp (SB16State *dsp)
bellard27503322003-11-13 01:46:15 +0000159{
bellard85571bc2004-11-07 18:04:02 +0000160 ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
161 dsp->fmt_stereo ? "Stereo" : "Mono",
162 dsp->fmt_signed ? "Signed" : "Unsigned",
163 dsp->fmt_bits,
164 dsp->dma_auto ? "Auto" : "Single",
165 dsp->block_size,
166 dsp->freq,
167 dsp->time_const,
168 dsp->speaker);
169}
170#endif
171
172static void speaker (SB16State *s, int on)
173{
174 s->speaker = on;
175 /* AUD_enable (s->voice, on); */
bellard27503322003-11-13 01:46:15 +0000176}
177
bellard85571bc2004-11-07 18:04:02 +0000178static void control (SB16State *s, int hold)
bellard27503322003-11-13 01:46:15 +0000179{
bellard85571bc2004-11-07 18:04:02 +0000180 int dma = s->use_hdma ? s->hdma : s->dma;
Hervé Poussineauf203c162016-02-03 11:28:58 -0500181 IsaDma *isa_dma = s->use_hdma ? s->isa_hdma : s->isa_dma;
182 IsaDmaClass *k = ISADMA_GET_CLASS(isa_dma);
bellard85571bc2004-11-07 18:04:02 +0000183 s->dma_running = hold;
184
185 ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma);
186
bellard27503322003-11-13 01:46:15 +0000187 if (hold) {
Hervé Poussineauf203c162016-02-03 11:28:58 -0500188 k->hold_DREQ(isa_dma, dma);
bellard1d14ffa2005-10-30 18:58:22 +0000189 AUD_set_active_out (s->voice, 1);
bellard27503322003-11-13 01:46:15 +0000190 }
191 else {
Hervé Poussineauf203c162016-02-03 11:28:58 -0500192 k->release_DREQ(isa_dma, dma);
bellard1d14ffa2005-10-30 18:58:22 +0000193 AUD_set_active_out (s->voice, 0);
bellard27503322003-11-13 01:46:15 +0000194 }
195}
196
bellard85571bc2004-11-07 18:04:02 +0000197static void aux_timer (void *opaque)
bellard27503322003-11-13 01:46:15 +0000198{
bellard85571bc2004-11-07 18:04:02 +0000199 SB16State *s = opaque;
200 s->can_write = 1;
Jes Sorensen3a38d432009-08-14 11:36:15 +0200201 qemu_irq_raise (s->pic);
bellard85571bc2004-11-07 18:04:02 +0000202}
bellard27503322003-11-13 01:46:15 +0000203
bellard85571bc2004-11-07 18:04:02 +0000204#define DMA8_AUTO 1
205#define DMA8_HIGH 2
206
bellardfeea13e2006-07-04 16:49:00 +0000207static void continue_dma8 (SB16State *s)
208{
209 if (s->freq > 0) {
malc1ea879e2008-12-03 22:48:44 +0000210 struct audsettings as;
bellardfeea13e2006-07-04 16:49:00 +0000211
212 s->audio_free = 0;
213
214 as.freq = s->freq;
215 as.nchannels = 1 << s->fmt_stereo;
216 as.fmt = s->fmt;
bellardd929eba2006-07-04 21:47:22 +0000217 as.endianness = 0;
bellardfeea13e2006-07-04 16:49:00 +0000218
219 s->voice = AUD_open_out (
220 &s->card,
221 s->voice,
222 "sb16",
223 s,
224 SB_audio_callback,
bellardd929eba2006-07-04 21:47:22 +0000225 &as
bellardfeea13e2006-07-04 16:49:00 +0000226 );
227 }
228
229 control (s, 1);
230}
231
Qiang Liu60e543f2021-06-24 10:44:47 +0800232static inline int restrict_sampling_rate(int freq)
233{
234 if (freq < SAMPLE_RATE_MIN) {
235 qemu_log_mask(LOG_GUEST_ERROR,
236 "sampling range too low: %d, increasing to %u\n",
237 freq, SAMPLE_RATE_MIN);
238 return SAMPLE_RATE_MIN;
239 } else if (freq > SAMPLE_RATE_MAX) {
240 qemu_log_mask(LOG_GUEST_ERROR,
241 "sampling range too high: %d, decreasing to %u\n",
242 freq, SAMPLE_RATE_MAX);
243 return SAMPLE_RATE_MAX;
244 } else {
245 return freq;
246 }
247}
248
bellard85571bc2004-11-07 18:04:02 +0000249static void dma_cmd8 (SB16State *s, int mask, int dma_len)
250{
Kővágó, Zoltán85bc5852019-03-08 23:34:13 +0100251 s->fmt = AUDIO_FORMAT_U8;
bellard85571bc2004-11-07 18:04:02 +0000252 s->use_hdma = 0;
253 s->fmt_bits = 8;
254 s->fmt_signed = 0;
255 s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
256 if (-1 == s->time_const) {
bellardfeea13e2006-07-04 16:49:00 +0000257 if (s->freq <= 0)
258 s->freq = 11025;
bellard85571bc2004-11-07 18:04:02 +0000259 }
260 else {
261 int tmp = (256 - s->time_const);
262 s->freq = (1000000 + (tmp / 2)) / tmp;
263 }
Qiang Liu60e543f2021-06-24 10:44:47 +0800264 s->freq = restrict_sampling_rate(s->freq);
bellard85571bc2004-11-07 18:04:02 +0000265
bellard1d14ffa2005-10-30 18:58:22 +0000266 if (dma_len != -1) {
bellard15b61472004-11-14 16:02:09 +0000267 s->block_size = dma_len << s->fmt_stereo;
bellard1d14ffa2005-10-30 18:58:22 +0000268 }
bellard15b61472004-11-14 16:02:09 +0000269 else {
270 /* This is apparently the only way to make both Act1/PL
271 and SecondReality/FC work
272
273 Act1 sets block size via command 0x48 and it's an odd number
274 SR does the same with even number
275 Both use stereo, and Creatives own documentation states that
276 0x48 sets block size in bytes less one.. go figure */
277 s->block_size &= ~s->fmt_stereo;
278 }
bellard85571bc2004-11-07 18:04:02 +0000279
280 s->freq >>= s->fmt_stereo;
281 s->left_till_irq = s->block_size;
282 s->bytes_per_second = (s->freq << s->fmt_stereo);
283 /* s->highspeed = (mask & DMA8_HIGH) != 0; */
284 s->dma_auto = (mask & DMA8_AUTO) != 0;
285 s->align = (1 << s->fmt_stereo) - 1;
286
bellard1d14ffa2005-10-30 18:58:22 +0000287 if (s->block_size & s->align) {
John Arbuckle8ec660b2018-02-01 12:27:44 -0500288 qemu_log_mask(LOG_GUEST_ERROR, "warning: misaligned block size %d,"
289 " alignment %d\n", s->block_size, s->align + 1);
bellard1d14ffa2005-10-30 18:58:22 +0000290 }
bellard15b61472004-11-14 16:02:09 +0000291
bellard85571bc2004-11-07 18:04:02 +0000292 ldebug ("freq %d, stereo %d, sign %d, bits %d, "
293 "dma %d, auto %d, fifo %d, high %d\n",
294 s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
295 s->block_size, s->dma_auto, s->fifo, s->highspeed);
296
bellardfeea13e2006-07-04 16:49:00 +0000297 continue_dma8 (s);
bellard85571bc2004-11-07 18:04:02 +0000298 speaker (s, 1);
299}
300
301static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
302{
303 s->use_hdma = cmd < 0xc0;
304 s->fifo = (cmd >> 1) & 1;
305 s->dma_auto = (cmd >> 2) & 1;
306 s->fmt_signed = (d0 >> 4) & 1;
307 s->fmt_stereo = (d0 >> 5) & 1;
bellard27503322003-11-13 01:46:15 +0000308
309 switch (cmd >> 4) {
310 case 11:
bellard85571bc2004-11-07 18:04:02 +0000311 s->fmt_bits = 16;
bellard27503322003-11-13 01:46:15 +0000312 break;
313
314 case 12:
bellard85571bc2004-11-07 18:04:02 +0000315 s->fmt_bits = 8;
bellard27503322003-11-13 01:46:15 +0000316 break;
317 }
318
bellard85571bc2004-11-07 18:04:02 +0000319 if (-1 != s->time_const) {
320#if 1
321 int tmp = 256 - s->time_const;
322 s->freq = (1000000 + (tmp / 2)) / tmp;
323#else
324 /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */
325 s->freq = 1000000 / ((255 - s->time_const));
326#endif
327 s->time_const = -1;
bellard27503322003-11-13 01:46:15 +0000328 }
bellard27503322003-11-13 01:46:15 +0000329
bellard85571bc2004-11-07 18:04:02 +0000330 s->block_size = dma_len + 1;
331 s->block_size <<= (s->fmt_bits == 16);
bellard15b61472004-11-14 16:02:09 +0000332 if (!s->dma_auto) {
333 /* It is clear that for DOOM and auto-init this value
334 shouldn't take stereo into account, while Miles Sound Systems
335 setsound.exe with single transfer mode wouldn't work without it
336 wonders of SB16 yet again */
bellard85571bc2004-11-07 18:04:02 +0000337 s->block_size <<= s->fmt_stereo;
bellard15b61472004-11-14 16:02:09 +0000338 }
bellard27503322003-11-13 01:46:15 +0000339
bellard85571bc2004-11-07 18:04:02 +0000340 ldebug ("freq %d, stereo %d, sign %d, bits %d, "
341 "dma %d, auto %d, fifo %d, high %d\n",
342 s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
343 s->block_size, s->dma_auto, s->fifo, s->highspeed);
bellard27503322003-11-13 01:46:15 +0000344
bellard85571bc2004-11-07 18:04:02 +0000345 if (16 == s->fmt_bits) {
346 if (s->fmt_signed) {
Kővágó, Zoltán85bc5852019-03-08 23:34:13 +0100347 s->fmt = AUDIO_FORMAT_S16;
bellard27503322003-11-13 01:46:15 +0000348 }
349 else {
Kővágó, Zoltán85bc5852019-03-08 23:34:13 +0100350 s->fmt = AUDIO_FORMAT_U16;
bellard27503322003-11-13 01:46:15 +0000351 }
352 }
353 else {
bellard85571bc2004-11-07 18:04:02 +0000354 if (s->fmt_signed) {
Kővágó, Zoltán85bc5852019-03-08 23:34:13 +0100355 s->fmt = AUDIO_FORMAT_S8;
bellard27503322003-11-13 01:46:15 +0000356 }
357 else {
Kővágó, Zoltán85bc5852019-03-08 23:34:13 +0100358 s->fmt = AUDIO_FORMAT_U8;
bellard27503322003-11-13 01:46:15 +0000359 }
360 }
361
bellard85571bc2004-11-07 18:04:02 +0000362 s->left_till_irq = s->block_size;
bellard27503322003-11-13 01:46:15 +0000363
bellard85571bc2004-11-07 18:04:02 +0000364 s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16);
365 s->highspeed = 0;
366 s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1;
bellard1d14ffa2005-10-30 18:58:22 +0000367 if (s->block_size & s->align) {
John Arbuckle8ec660b2018-02-01 12:27:44 -0500368 qemu_log_mask(LOG_GUEST_ERROR, "warning: misaligned block size %d,"
369 " alignment %d\n", s->block_size, s->align + 1);
bellard1d14ffa2005-10-30 18:58:22 +0000370 }
bellard85571bc2004-11-07 18:04:02 +0000371
bellard1d14ffa2005-10-30 18:58:22 +0000372 if (s->freq) {
malc1ea879e2008-12-03 22:48:44 +0000373 struct audsettings as;
bellardc0fe3822005-11-05 18:55:28 +0000374
bellard1d14ffa2005-10-30 18:58:22 +0000375 s->audio_free = 0;
bellardc0fe3822005-11-05 18:55:28 +0000376
377 as.freq = s->freq;
378 as.nchannels = 1 << s->fmt_stereo;
379 as.fmt = s->fmt;
bellardd929eba2006-07-04 21:47:22 +0000380 as.endianness = 0;
bellardc0fe3822005-11-05 18:55:28 +0000381
bellard1d14ffa2005-10-30 18:58:22 +0000382 s->voice = AUD_open_out (
bellardc0fe3822005-11-05 18:55:28 +0000383 &s->card,
bellard1d14ffa2005-10-30 18:58:22 +0000384 s->voice,
385 "sb16",
386 s,
387 SB_audio_callback,
bellardd929eba2006-07-04 21:47:22 +0000388 &as
bellard1d14ffa2005-10-30 18:58:22 +0000389 );
390 }
bellard85571bc2004-11-07 18:04:02 +0000391
392 control (s, 1);
393 speaker (s, 1);
394}
395
396static inline void dsp_out_data (SB16State *s, uint8_t val)
397{
398 ldebug ("outdata %#x\n", val);
bellardc0fe3822005-11-05 18:55:28 +0000399 if ((size_t) s->out_data_len < sizeof (s->out_data)) {
bellard85571bc2004-11-07 18:04:02 +0000400 s->out_data[s->out_data_len++] = val;
bellard1d14ffa2005-10-30 18:58:22 +0000401 }
bellard85571bc2004-11-07 18:04:02 +0000402}
403
404static inline uint8_t dsp_get_data (SB16State *s)
405{
bellard1d14ffa2005-10-30 18:58:22 +0000406 if (s->in_index) {
bellard85571bc2004-11-07 18:04:02 +0000407 return s->in2_data[--s->in_index];
bellard1d14ffa2005-10-30 18:58:22 +0000408 }
bellard27503322003-11-13 01:46:15 +0000409 else {
bellard85571bc2004-11-07 18:04:02 +0000410 dolog ("buffer underflow\n");
bellardd75d9f62004-10-09 17:20:54 +0000411 return 0;
bellard85571bc2004-11-07 18:04:02 +0000412 }
bellardd75d9f62004-10-09 17:20:54 +0000413}
414
bellard85571bc2004-11-07 18:04:02 +0000415static void command (SB16State *s, uint8_t cmd)
bellard27503322003-11-13 01:46:15 +0000416{
bellard85571bc2004-11-07 18:04:02 +0000417 ldebug ("command %#x\n", cmd);
bellard27503322003-11-13 01:46:15 +0000418
419 if (cmd > 0xaf && cmd < 0xd0) {
bellard85571bc2004-11-07 18:04:02 +0000420 if (cmd & 8) {
John Arbuckle8ec660b2018-02-01 12:27:44 -0500421 qemu_log_mask(LOG_UNIMP, "ADC not yet supported (command %#x)\n",
422 cmd);
bellard85571bc2004-11-07 18:04:02 +0000423 }
bellard27503322003-11-13 01:46:15 +0000424
425 switch (cmd >> 4) {
426 case 11:
427 case 12:
428 break;
429 default:
John Arbuckle8ec660b2018-02-01 12:27:44 -0500430 qemu_log_mask(LOG_GUEST_ERROR, "%#x wrong bits\n", cmd);
bellard27503322003-11-13 01:46:15 +0000431 }
bellard85571bc2004-11-07 18:04:02 +0000432 s->needed_bytes = 3;
bellard27503322003-11-13 01:46:15 +0000433 }
434 else {
bellard1d14ffa2005-10-30 18:58:22 +0000435 s->needed_bytes = 0;
436
bellard27503322003-11-13 01:46:15 +0000437 switch (cmd) {
bellardd75d9f62004-10-09 17:20:54 +0000438 case 0x03:
bellard85571bc2004-11-07 18:04:02 +0000439 dsp_out_data (s, 0x10); /* s->csp_param); */
440 goto warn;
441
bellardd329a6f2004-06-07 20:58:31 +0000442 case 0x04:
bellard85571bc2004-11-07 18:04:02 +0000443 s->needed_bytes = 1;
444 goto warn;
bellardd329a6f2004-06-07 20:58:31 +0000445
446 case 0x05:
bellard85571bc2004-11-07 18:04:02 +0000447 s->needed_bytes = 2;
448 goto warn;
449
450 case 0x08:
451 /* __asm__ ("int3"); */
452 goto warn;
bellardd75d9f62004-10-09 17:20:54 +0000453
bellardd329a6f2004-06-07 20:58:31 +0000454 case 0x0e:
bellard85571bc2004-11-07 18:04:02 +0000455 s->needed_bytes = 2;
456 goto warn;
457
458 case 0x09:
459 dsp_out_data (s, 0xf8);
460 goto warn;
bellardd329a6f2004-06-07 20:58:31 +0000461
462 case 0x0f:
bellard85571bc2004-11-07 18:04:02 +0000463 s->needed_bytes = 1;
464 goto warn;
bellardd329a6f2004-06-07 20:58:31 +0000465
bellard27503322003-11-13 01:46:15 +0000466 case 0x10:
bellard85571bc2004-11-07 18:04:02 +0000467 s->needed_bytes = 1;
468 goto warn;
bellard27503322003-11-13 01:46:15 +0000469
470 case 0x14:
bellard85571bc2004-11-07 18:04:02 +0000471 s->needed_bytes = 2;
472 s->block_size = 0;
bellard27503322003-11-13 01:46:15 +0000473 break;
474
bellard15b61472004-11-14 16:02:09 +0000475 case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */
bellardfeea13e2006-07-04 16:49:00 +0000476 dma_cmd8 (s, DMA8_AUTO, -1);
bellard15b61472004-11-14 16:02:09 +0000477 break;
478
bellard85571bc2004-11-07 18:04:02 +0000479 case 0x20: /* Direct ADC, Juice/PL */
480 dsp_out_data (s, 0xff);
481 goto warn;
bellard27503322003-11-13 01:46:15 +0000482
483 case 0x35:
John Arbuckle8ec660b2018-02-01 12:27:44 -0500484 qemu_log_mask(LOG_UNIMP, "0x35 - MIDI command not implemented\n");
bellard27503322003-11-13 01:46:15 +0000485 break;
486
487 case 0x40:
bellard85571bc2004-11-07 18:04:02 +0000488 s->freq = -1;
489 s->time_const = -1;
490 s->needed_bytes = 1;
bellard27503322003-11-13 01:46:15 +0000491 break;
492
493 case 0x41:
bellard85571bc2004-11-07 18:04:02 +0000494 s->freq = -1;
495 s->time_const = -1;
496 s->needed_bytes = 2;
bellard27503322003-11-13 01:46:15 +0000497 break;
498
bellard85571bc2004-11-07 18:04:02 +0000499 case 0x42:
500 s->freq = -1;
501 s->time_const = -1;
502 s->needed_bytes = 2;
503 goto warn;
504
bellardd75d9f62004-10-09 17:20:54 +0000505 case 0x45:
bellard85571bc2004-11-07 18:04:02 +0000506 dsp_out_data (s, 0xaa);
507 goto warn;
508
bellard27503322003-11-13 01:46:15 +0000509 case 0x47: /* Continue Auto-Initialize DMA 16bit */
510 break;
511
512 case 0x48:
bellard85571bc2004-11-07 18:04:02 +0000513 s->needed_bytes = 2;
bellard27503322003-11-13 01:46:15 +0000514 break;
515
bellard1d14ffa2005-10-30 18:58:22 +0000516 case 0x74:
517 s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
John Arbuckle8ec660b2018-02-01 12:27:44 -0500518 qemu_log_mask(LOG_UNIMP, "0x75 - DMA DAC, 4-bit ADPCM not"
519 " implemented\n");
bellard1d14ffa2005-10-30 18:58:22 +0000520 break;
521
522 case 0x75: /* DMA DAC, 4-bit ADPCM Reference */
523 s->needed_bytes = 2;
John Arbuckle8ec660b2018-02-01 12:27:44 -0500524 qemu_log_mask(LOG_UNIMP, "0x74 - DMA DAC, 4-bit ADPCM Reference not"
525 " implemented\n");
bellard1d14ffa2005-10-30 18:58:22 +0000526 break;
527
528 case 0x76: /* DMA DAC, 2.6-bit ADPCM */
529 s->needed_bytes = 2;
John Arbuckle8ec660b2018-02-01 12:27:44 -0500530 qemu_log_mask(LOG_UNIMP, "0x74 - DMA DAC, 2.6-bit ADPCM not"
531 " implemented\n");
bellard1d14ffa2005-10-30 18:58:22 +0000532 break;
533
534 case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */
535 s->needed_bytes = 2;
John Arbuckle8ec660b2018-02-01 12:27:44 -0500536 qemu_log_mask(LOG_UNIMP, "0x74 - DMA DAC, 2.6-bit ADPCM Reference"
537 " not implemented\n");
bellard1d14ffa2005-10-30 18:58:22 +0000538 break;
539
540 case 0x7d:
John Arbuckle8ec660b2018-02-01 12:27:44 -0500541 qemu_log_mask(LOG_UNIMP, "0x7d - Autio-Initialize DMA DAC, 4-bit"
542 " ADPCM Reference\n");
543 qemu_log_mask(LOG_UNIMP, "not implemented\n");
bellard1d14ffa2005-10-30 18:58:22 +0000544 break;
545
546 case 0x7f:
John Arbuckle8ec660b2018-02-01 12:27:44 -0500547 qemu_log_mask(LOG_UNIMP, "0x7d - Autio-Initialize DMA DAC, 2.6-bit"
548 " ADPCM Reference\n");
549 qemu_log_mask(LOG_UNIMP, "not implemented\n");
bellard1d14ffa2005-10-30 18:58:22 +0000550 break;
551
bellard27503322003-11-13 01:46:15 +0000552 case 0x80:
bellard85571bc2004-11-07 18:04:02 +0000553 s->needed_bytes = 2;
bellard27503322003-11-13 01:46:15 +0000554 break;
555
556 case 0x90:
557 case 0x91:
bellard85571bc2004-11-07 18:04:02 +0000558 dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1);
bellard27503322003-11-13 01:46:15 +0000559 break;
560
bellard85571bc2004-11-07 18:04:02 +0000561 case 0xd0: /* halt DMA operation. 8bit */
562 control (s, 0);
bellard27503322003-11-13 01:46:15 +0000563 break;
564
bellard85571bc2004-11-07 18:04:02 +0000565 case 0xd1: /* speaker on */
566 speaker (s, 1);
bellard27503322003-11-13 01:46:15 +0000567 break;
568
bellard85571bc2004-11-07 18:04:02 +0000569 case 0xd3: /* speaker off */
570 speaker (s, 0);
bellard27503322003-11-13 01:46:15 +0000571 break;
572
bellard85571bc2004-11-07 18:04:02 +0000573 case 0xd4: /* continue DMA operation. 8bit */
bellardfeea13e2006-07-04 16:49:00 +0000574 /* KQ6 (or maybe Sierras audblst.drv in general) resets
575 the frequency between halt/continue */
576 continue_dma8 (s);
bellard85571bc2004-11-07 18:04:02 +0000577 break;
bellard27503322003-11-13 01:46:15 +0000578
bellard85571bc2004-11-07 18:04:02 +0000579 case 0xd5: /* halt DMA operation. 16bit */
580 control (s, 0);
581 break;
582
583 case 0xd6: /* continue DMA operation. 16bit */
584 control (s, 1);
585 break;
586
587 case 0xd9: /* exit auto-init DMA after this block. 16bit */
588 s->dma_auto = 0;
589 break;
590
591 case 0xda: /* exit auto-init DMA after this block. 8bit */
592 s->dma_auto = 0;
bellard27503322003-11-13 01:46:15 +0000593 break;
594
bellard1d14ffa2005-10-30 18:58:22 +0000595 case 0xe0: /* DSP identification */
bellard85571bc2004-11-07 18:04:02 +0000596 s->needed_bytes = 1;
bellard1d14ffa2005-10-30 18:58:22 +0000597 break;
bellard27503322003-11-13 01:46:15 +0000598
599 case 0xe1:
bellard85571bc2004-11-07 18:04:02 +0000600 dsp_out_data (s, s->ver & 0xff);
601 dsp_out_data (s, s->ver >> 8);
602 break;
603
604 case 0xe2:
605 s->needed_bytes = 1;
606 goto warn;
bellard27503322003-11-13 01:46:15 +0000607
bellardd329a6f2004-06-07 20:58:31 +0000608 case 0xe3:
609 {
610 int i;
bellard85571bc2004-11-07 18:04:02 +0000611 for (i = sizeof (e3) - 1; i >= 0; --i)
612 dsp_out_data (s, e3[i]);
bellardd329a6f2004-06-07 20:58:31 +0000613 }
bellardd75d9f62004-10-09 17:20:54 +0000614 break;
615
bellard85571bc2004-11-07 18:04:02 +0000616 case 0xe4: /* write test reg */
617 s->needed_bytes = 1;
618 break;
619
620 case 0xe7:
John Arbuckle8ec660b2018-02-01 12:27:44 -0500621 qemu_log_mask(LOG_UNIMP, "Attempt to probe for ESS (0xe7)?\n");
bellard1d14ffa2005-10-30 18:58:22 +0000622 break;
bellard85571bc2004-11-07 18:04:02 +0000623
bellardd75d9f62004-10-09 17:20:54 +0000624 case 0xe8: /* read test reg */
bellard85571bc2004-11-07 18:04:02 +0000625 dsp_out_data (s, s->test_reg);
bellardd75d9f62004-10-09 17:20:54 +0000626 break;
627
bellard27503322003-11-13 01:46:15 +0000628 case 0xf2:
bellard85571bc2004-11-07 18:04:02 +0000629 case 0xf3:
630 dsp_out_data (s, 0xaa);
631 s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
Jes Sorensen3a38d432009-08-14 11:36:15 +0200632 qemu_irq_raise (s->pic);
bellard85571bc2004-11-07 18:04:02 +0000633 break;
bellard27503322003-11-13 01:46:15 +0000634
bellardd75d9f62004-10-09 17:20:54 +0000635 case 0xf9:
bellard85571bc2004-11-07 18:04:02 +0000636 s->needed_bytes = 1;
637 goto warn;
bellardd75d9f62004-10-09 17:20:54 +0000638
639 case 0xfa:
bellard85571bc2004-11-07 18:04:02 +0000640 dsp_out_data (s, 0);
641 goto warn;
bellardd75d9f62004-10-09 17:20:54 +0000642
643 case 0xfc: /* FIXME */
bellard85571bc2004-11-07 18:04:02 +0000644 dsp_out_data (s, 0);
645 goto warn;
bellardd75d9f62004-10-09 17:20:54 +0000646
bellard27503322003-11-13 01:46:15 +0000647 default:
John Arbuckle8ec660b2018-02-01 12:27:44 -0500648 qemu_log_mask(LOG_UNIMP, "Unrecognized command %#x\n", cmd);
bellard1d14ffa2005-10-30 18:58:22 +0000649 break;
bellard27503322003-11-13 01:46:15 +0000650 }
651 }
652
bellard1d14ffa2005-10-30 18:58:22 +0000653 if (!s->needed_bytes) {
bellard85571bc2004-11-07 18:04:02 +0000654 ldebug ("\n");
bellard1d14ffa2005-10-30 18:58:22 +0000655 }
656
657 exit:
658 if (!s->needed_bytes) {
659 s->cmd = -1;
660 }
661 else {
662 s->cmd = cmd;
663 }
bellard27503322003-11-13 01:46:15 +0000664 return;
bellard85571bc2004-11-07 18:04:02 +0000665
666 warn:
John Arbuckle8ec660b2018-02-01 12:27:44 -0500667 qemu_log_mask(LOG_UNIMP, "warning: command %#x,%d is not truly understood"
668 " yet\n", cmd, s->needed_bytes);
bellard1d14ffa2005-10-30 18:58:22 +0000669 goto exit;
670
bellard85571bc2004-11-07 18:04:02 +0000671}
672
673static uint16_t dsp_get_lohi (SB16State *s)
674{
675 uint8_t hi = dsp_get_data (s);
676 uint8_t lo = dsp_get_data (s);
677 return (hi << 8) | lo;
678}
679
680static uint16_t dsp_get_hilo (SB16State *s)
681{
682 uint8_t lo = dsp_get_data (s);
683 uint8_t hi = dsp_get_data (s);
684 return (hi << 8) | lo;
685}
686
687static void complete (SB16State *s)
688{
689 int d0, d1, d2;
690 ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
691 s->cmd, s->in_index, s->needed_bytes);
692
693 if (s->cmd > 0xaf && s->cmd < 0xd0) {
694 d2 = dsp_get_data (s);
695 d1 = dsp_get_data (s);
696 d0 = dsp_get_data (s);
697
698 if (s->cmd & 8) {
699 dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
700 s->cmd, d0, d1, d2);
701 }
702 else {
703 ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
704 s->cmd, d0, d1, d2);
705 dma_cmd (s, s->cmd, d0, d1 + (d2 << 8));
706 }
707 }
708 else {
709 switch (s->cmd) {
710 case 0x04:
711 s->csp_mode = dsp_get_data (s);
712 s->csp_reg83r = 0;
713 s->csp_reg83w = 0;
714 ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode);
715 break;
716
717 case 0x05:
718 s->csp_param = dsp_get_data (s);
719 s->csp_value = dsp_get_data (s);
720 ldebug ("CSP command 0x05: param=%#x value=%#x\n",
721 s->csp_param,
722 s->csp_value);
723 break;
724
725 case 0x0e:
726 d0 = dsp_get_data (s);
727 d1 = dsp_get_data (s);
728 ldebug ("write CSP register %d <- %#x\n", d1, d0);
729 if (d1 == 0x83) {
730 ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0);
731 s->csp_reg83[s->csp_reg83r % 4] = d0;
732 s->csp_reg83r += 1;
733 }
bellard1d14ffa2005-10-30 18:58:22 +0000734 else {
bellard85571bc2004-11-07 18:04:02 +0000735 s->csp_regs[d1] = d0;
bellard1d14ffa2005-10-30 18:58:22 +0000736 }
bellard85571bc2004-11-07 18:04:02 +0000737 break;
738
739 case 0x0f:
740 d0 = dsp_get_data (s);
741 ldebug ("read CSP register %#x -> %#x, mode=%#x\n",
742 d0, s->csp_regs[d0], s->csp_mode);
743 if (d0 == 0x83) {
744 ldebug ("0x83[%d] -> %#x\n",
745 s->csp_reg83w,
746 s->csp_reg83[s->csp_reg83w % 4]);
747 dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]);
748 s->csp_reg83w += 1;
749 }
bellard1d14ffa2005-10-30 18:58:22 +0000750 else {
bellard85571bc2004-11-07 18:04:02 +0000751 dsp_out_data (s, s->csp_regs[d0]);
bellard1d14ffa2005-10-30 18:58:22 +0000752 }
bellard85571bc2004-11-07 18:04:02 +0000753 break;
754
755 case 0x10:
756 d0 = dsp_get_data (s);
757 dolog ("cmd 0x10 d0=%#x\n", d0);
758 break;
759
760 case 0x14:
bellard15b61472004-11-14 16:02:09 +0000761 dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
bellard85571bc2004-11-07 18:04:02 +0000762 break;
763
764 case 0x40:
765 s->time_const = dsp_get_data (s);
766 ldebug ("set time const %d\n", s->time_const);
767 break;
768
bellard85571bc2004-11-07 18:04:02 +0000769 case 0x41:
Paolo Bonziniedd75412018-08-01 17:14:09 +0200770 case 0x42:
771 /*
772 * 0x41 is documented as setting the output sample rate,
773 * and 0x42 the input sample rate, but in fact SB16 hardware
774 * seems to have only a single sample rate under the hood,
775 * and FT2 sets output freq with this (go figure). Compare:
776 * http://homepages.cae.wisc.edu/~brodskye/sb16doc/sb16doc.html#SamplingRate
777 */
Qiang Liu60e543f2021-06-24 10:44:47 +0800778 s->freq = restrict_sampling_rate(dsp_get_hilo(s));
bellard85571bc2004-11-07 18:04:02 +0000779 ldebug ("set freq %d\n", s->freq);
780 break;
781
782 case 0x48:
bellard15b61472004-11-14 16:02:09 +0000783 s->block_size = dsp_get_lohi (s) + 1;
bellard85571bc2004-11-07 18:04:02 +0000784 ldebug ("set dma block len %d\n", s->block_size);
785 break;
786
bellard1d14ffa2005-10-30 18:58:22 +0000787 case 0x74:
788 case 0x75:
789 case 0x76:
790 case 0x77:
791 /* ADPCM stuff, ignore */
792 break;
793
bellard85571bc2004-11-07 18:04:02 +0000794 case 0x80:
795 {
bellard15b61472004-11-14 16:02:09 +0000796 int freq, samples, bytes;
bellard85571bc2004-11-07 18:04:02 +0000797 int64_t ticks;
798
bellard15b61472004-11-14 16:02:09 +0000799 freq = s->freq > 0 ? s->freq : 11025;
800 samples = dsp_get_lohi (s) + 1;
bellard85571bc2004-11-07 18:04:02 +0000801 bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
Rutuja Shah73bcb242016-03-21 21:32:30 +0530802 ticks = muldiv64(bytes, NANOSECONDS_PER_SECOND, freq);
803 if (ticks < NANOSECONDS_PER_SECOND / 1024) {
Jes Sorensen3a38d432009-08-14 11:36:15 +0200804 qemu_irq_raise (s->pic);
bellard1d14ffa2005-10-30 18:58:22 +0000805 }
806 else {
807 if (s->aux_ts) {
Alex Blighbc72ad62013-08-21 16:03:08 +0100808 timer_mod (
bellard1d14ffa2005-10-30 18:58:22 +0000809 s->aux_ts,
Alex Blighbc72ad62013-08-21 16:03:08 +0100810 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks
bellard1d14ffa2005-10-30 18:58:22 +0000811 );
812 }
813 }
bellard26a76462006-06-25 18:15:32 +0000814 ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks);
bellard85571bc2004-11-07 18:04:02 +0000815 }
816 break;
817
818 case 0xe0:
819 d0 = dsp_get_data (s);
820 s->out_data_len = 0;
821 ldebug ("E0 data = %#x\n", d0);
bellard1d14ffa2005-10-30 18:58:22 +0000822 dsp_out_data (s, ~d0);
bellard85571bc2004-11-07 18:04:02 +0000823 break;
824
825 case 0xe2:
malc514d97d2010-01-12 21:55:45 +0300826#ifdef DEBUG
bellard85571bc2004-11-07 18:04:02 +0000827 d0 = dsp_get_data (s);
malc514d97d2010-01-12 21:55:45 +0300828 dolog ("E2 = %#x\n", d0);
829#endif
bellard85571bc2004-11-07 18:04:02 +0000830 break;
831
832 case 0xe4:
833 s->test_reg = dsp_get_data (s);
834 break;
835
836 case 0xf9:
837 d0 = dsp_get_data (s);
838 ldebug ("command 0xf9 with %#x\n", d0);
839 switch (d0) {
840 case 0x0e:
841 dsp_out_data (s, 0xff);
842 break;
843
844 case 0x0f:
845 dsp_out_data (s, 0x07);
846 break;
847
848 case 0x37:
849 dsp_out_data (s, 0x38);
850 break;
851
852 default:
853 dsp_out_data (s, 0x00);
854 break;
855 }
856 break;
857
858 default:
John Arbuckle8ec660b2018-02-01 12:27:44 -0500859 qemu_log_mask(LOG_UNIMP, "complete: unrecognized command %#x\n",
860 s->cmd);
bellard85571bc2004-11-07 18:04:02 +0000861 return;
862 }
863 }
864
865 ldebug ("\n");
866 s->cmd = -1;
bellard85571bc2004-11-07 18:04:02 +0000867}
868
bellardfeea13e2006-07-04 16:49:00 +0000869static void legacy_reset (SB16State *s)
870{
malc1ea879e2008-12-03 22:48:44 +0000871 struct audsettings as;
bellardfeea13e2006-07-04 16:49:00 +0000872
873 s->freq = 11025;
874 s->fmt_signed = 0;
875 s->fmt_bits = 8;
876 s->fmt_stereo = 0;
877
878 as.freq = s->freq;
879 as.nchannels = 1;
Kővágó, Zoltán85bc5852019-03-08 23:34:13 +0100880 as.fmt = AUDIO_FORMAT_U8;
bellardd929eba2006-07-04 21:47:22 +0000881 as.endianness = 0;
bellardfeea13e2006-07-04 16:49:00 +0000882
883 s->voice = AUD_open_out (
884 &s->card,
885 s->voice,
886 "sb16",
887 s,
888 SB_audio_callback,
bellardd929eba2006-07-04 21:47:22 +0000889 &as
bellardfeea13e2006-07-04 16:49:00 +0000890 );
891
892 /* Not sure about that... */
893 /* AUD_set_active_out (s->voice, 1); */
894}
895
bellard85571bc2004-11-07 18:04:02 +0000896static void reset (SB16State *s)
897{
Jes Sorensen3a38d432009-08-14 11:36:15 +0200898 qemu_irq_lower (s->pic);
bellard85571bc2004-11-07 18:04:02 +0000899 if (s->dma_auto) {
Jes Sorensen3a38d432009-08-14 11:36:15 +0200900 qemu_irq_raise (s->pic);
901 qemu_irq_lower (s->pic);
bellard85571bc2004-11-07 18:04:02 +0000902 }
903
904 s->mixer_regs[0x82] = 0;
905 s->dma_auto = 0;
906 s->in_index = 0;
907 s->out_data_len = 0;
908 s->left_till_irq = 0;
909 s->needed_bytes = 0;
910 s->block_size = -1;
911 s->nzero = 0;
912 s->highspeed = 0;
913 s->v2x6 = 0;
bellard1d14ffa2005-10-30 18:58:22 +0000914 s->cmd = -1;
bellard85571bc2004-11-07 18:04:02 +0000915
malc31226162009-09-10 19:59:50 +0400916 dsp_out_data (s, 0xaa);
bellard85571bc2004-11-07 18:04:02 +0000917 speaker (s, 0);
918 control (s, 0);
bellardfeea13e2006-07-04 16:49:00 +0000919 legacy_reset (s);
bellard27503322003-11-13 01:46:15 +0000920}
921
Nutan Shinde8307c292015-10-07 22:02:54 +0530922static void dsp_write(void *opaque, uint32_t nport, uint32_t val)
bellard27503322003-11-13 01:46:15 +0000923{
bellard85571bc2004-11-07 18:04:02 +0000924 SB16State *s = opaque;
bellard27503322003-11-13 01:46:15 +0000925 int iport;
926
bellard85571bc2004-11-07 18:04:02 +0000927 iport = nport - s->port;
bellard27503322003-11-13 01:46:15 +0000928
bellard85571bc2004-11-07 18:04:02 +0000929 ldebug ("write %#x <- %#x\n", nport, val);
bellard27503322003-11-13 01:46:15 +0000930 switch (iport) {
bellard85571bc2004-11-07 18:04:02 +0000931 case 0x06:
932 switch (val) {
933 case 0x00:
934 if (s->v2x6 == 1) {
malccd7aafc2009-11-18 19:17:03 +0300935 reset (s);
bellard85571bc2004-11-07 18:04:02 +0000936 }
937 s->v2x6 = 0;
938 break;
939
940 case 0x01:
941 case 0x03: /* FreeBSD kludge */
942 s->v2x6 = 1;
943 break;
944
945 case 0xc6:
946 s->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */
947 break;
948
949 case 0xb8: /* Panic */
950 reset (s);
951 break;
952
953 case 0x39:
954 dsp_out_data (s, 0x38);
955 reset (s);
956 s->v2x6 = 0x39;
957 break;
958
959 default:
960 s->v2x6 = val;
961 break;
bellard27503322003-11-13 01:46:15 +0000962 }
bellard27503322003-11-13 01:46:15 +0000963 break;
964
bellard85571bc2004-11-07 18:04:02 +0000965 case 0x0c: /* write data or command | write status */
966/* if (s->highspeed) */
967/* break; */
968
Gonglei2ab5bf62014-08-11 21:00:53 +0800969 if (s->needed_bytes == 0) {
bellard85571bc2004-11-07 18:04:02 +0000970 command (s, val);
971#if 0
972 if (0 == s->needed_bytes) {
973 log_dsp (s);
bellard27503322003-11-13 01:46:15 +0000974 }
bellard85571bc2004-11-07 18:04:02 +0000975#endif
bellard27503322003-11-13 01:46:15 +0000976 }
977 else {
bellard85571bc2004-11-07 18:04:02 +0000978 if (s->in_index == sizeof (s->in2_data)) {
bellardd75d9f62004-10-09 17:20:54 +0000979 dolog ("in data overrun\n");
980 }
981 else {
bellard85571bc2004-11-07 18:04:02 +0000982 s->in2_data[s->in_index++] = val;
983 if (s->in_index == s->needed_bytes) {
984 s->needed_bytes = 0;
985 complete (s);
986#if 0
987 log_dsp (s);
988#endif
989 }
bellard27503322003-11-13 01:46:15 +0000990 }
991 }
992 break;
993
994 default:
bellard85571bc2004-11-07 18:04:02 +0000995 ldebug ("(nport=%#x, val=%#x)\n", nport, val);
bellard5e2a6442004-03-23 22:42:11 +0000996 break;
bellard27503322003-11-13 01:46:15 +0000997 }
998}
999
Nutan Shinde8307c292015-10-07 22:02:54 +05301000static uint32_t dsp_read(void *opaque, uint32_t nport)
bellard27503322003-11-13 01:46:15 +00001001{
bellard85571bc2004-11-07 18:04:02 +00001002 SB16State *s = opaque;
1003 int iport, retval, ack = 0;
bellard27503322003-11-13 01:46:15 +00001004
bellard85571bc2004-11-07 18:04:02 +00001005 iport = nport - s->port;
bellard27503322003-11-13 01:46:15 +00001006
1007 switch (iport) {
bellard85571bc2004-11-07 18:04:02 +00001008 case 0x06: /* reset */
1009 retval = 0xff;
bellardd75d9f62004-10-09 17:20:54 +00001010 break;
bellard27503322003-11-13 01:46:15 +00001011
bellard85571bc2004-11-07 18:04:02 +00001012 case 0x0a: /* read data */
1013 if (s->out_data_len) {
1014 retval = s->out_data[--s->out_data_len];
1015 s->last_read_byte = retval;
1016 }
1017 else {
bellard1d14ffa2005-10-30 18:58:22 +00001018 if (s->cmd != -1) {
1019 dolog ("empty output buffer for command %#x\n",
1020 s->cmd);
1021 }
bellard85571bc2004-11-07 18:04:02 +00001022 retval = s->last_read_byte;
bellardd75d9f62004-10-09 17:20:54 +00001023 /* goto error; */
bellard27503322003-11-13 01:46:15 +00001024 }
1025 break;
1026
bellard85571bc2004-11-07 18:04:02 +00001027 case 0x0c: /* 0 can write */
1028 retval = s->can_write ? 0 : 0x80;
1029 break;
1030
1031 case 0x0d: /* timer interrupt clear */
1032 /* dolog ("timer interrupt clear\n"); */
bellard27503322003-11-13 01:46:15 +00001033 retval = 0;
1034 break;
1035
bellard85571bc2004-11-07 18:04:02 +00001036 case 0x0e: /* data available status | irq 8 ack */
1037 retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
1038 if (s->mixer_regs[0x82] & 1) {
1039 ack = 1;
Paolo Bonzini99393752015-01-20 17:23:48 +01001040 s->mixer_regs[0x82] &= ~1;
Jes Sorensen3a38d432009-08-14 11:36:15 +02001041 qemu_irq_lower (s->pic);
bellard85571bc2004-11-07 18:04:02 +00001042 }
bellard27503322003-11-13 01:46:15 +00001043 break;
1044
bellard85571bc2004-11-07 18:04:02 +00001045 case 0x0f: /* irq 16 ack */
bellardbc0b1dc2004-01-18 22:19:31 +00001046 retval = 0xff;
bellard85571bc2004-11-07 18:04:02 +00001047 if (s->mixer_regs[0x82] & 2) {
1048 ack = 1;
Paolo Bonzini99393752015-01-20 17:23:48 +01001049 s->mixer_regs[0x82] &= ~2;
Jes Sorensen3a38d432009-08-14 11:36:15 +02001050 qemu_irq_lower (s->pic);
bellard85571bc2004-11-07 18:04:02 +00001051 }
bellard27503322003-11-13 01:46:15 +00001052 break;
1053
1054 default:
1055 goto error;
1056 }
1057
bellard1d14ffa2005-10-30 18:58:22 +00001058 if (!ack) {
bellard85571bc2004-11-07 18:04:02 +00001059 ldebug ("read %#x -> %#x\n", nport, retval);
bellard1d14ffa2005-10-30 18:58:22 +00001060 }
bellard27503322003-11-13 01:46:15 +00001061
1062 return retval;
1063
1064 error:
bellard1d14ffa2005-10-30 18:58:22 +00001065 dolog ("warning: dsp_read %#x error\n", nport);
bellardd75d9f62004-10-09 17:20:54 +00001066 return 0xff;
bellard27503322003-11-13 01:46:15 +00001067}
1068
bellard85571bc2004-11-07 18:04:02 +00001069static void reset_mixer (SB16State *s)
1070{
1071 int i;
1072
1073 memset (s->mixer_regs, 0xff, 0x7f);
1074 memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83);
1075
1076 s->mixer_regs[0x02] = 4; /* master volume 3bits */
1077 s->mixer_regs[0x06] = 4; /* MIDI volume 3bits */
1078 s->mixer_regs[0x08] = 0; /* CD volume 3bits */
1079 s->mixer_regs[0x0a] = 0; /* voice volume 2bits */
1080
1081 /* d5=input filt, d3=lowpass filt, d1,d2=input source */
1082 s->mixer_regs[0x0c] = 0;
1083
1084 /* d5=output filt, d1=stereo switch */
1085 s->mixer_regs[0x0e] = 0;
1086
1087 /* voice volume L d5,d7, R d1,d3 */
1088 s->mixer_regs[0x04] = (4 << 5) | (4 << 1);
1089 /* master ... */
1090 s->mixer_regs[0x22] = (4 << 5) | (4 << 1);
1091 /* MIDI ... */
1092 s->mixer_regs[0x26] = (4 << 5) | (4 << 1);
1093
1094 for (i = 0x30; i < 0x48; i++) {
1095 s->mixer_regs[i] = 0x20;
1096 }
1097}
1098
Nutan Shinde8307c292015-10-07 22:02:54 +05301099static void mixer_write_indexb(void *opaque, uint32_t nport, uint32_t val)
bellard27503322003-11-13 01:46:15 +00001100{
bellard85571bc2004-11-07 18:04:02 +00001101 SB16State *s = opaque;
bellardc0fe3822005-11-05 18:55:28 +00001102 (void) nport;
bellard85571bc2004-11-07 18:04:02 +00001103 s->mixer_nreg = val;
bellard27503322003-11-13 01:46:15 +00001104}
1105
Nutan Shinde8307c292015-10-07 22:02:54 +05301106static void mixer_write_datab(void *opaque, uint32_t nport, uint32_t val)
bellard27503322003-11-13 01:46:15 +00001107{
bellard85571bc2004-11-07 18:04:02 +00001108 SB16State *s = opaque;
bellard202a4562004-04-16 22:09:02 +00001109
bellardc0fe3822005-11-05 18:55:28 +00001110 (void) nport;
bellard85571bc2004-11-07 18:04:02 +00001111 ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
bellard85571bc2004-11-07 18:04:02 +00001112
1113 switch (s->mixer_nreg) {
bellardd75d9f62004-10-09 17:20:54 +00001114 case 0x00:
bellard85571bc2004-11-07 18:04:02 +00001115 reset_mixer (s);
1116 break;
bellardd75d9f62004-10-09 17:20:54 +00001117
bellard85571bc2004-11-07 18:04:02 +00001118 case 0x80:
1119 {
1120 int irq = irq_of_magic (val);
1121 ldebug ("setting irq to %d (val=%#x)\n", irq, val);
bellard1d14ffa2005-10-30 18:58:22 +00001122 if (irq > 0) {
bellard85571bc2004-11-07 18:04:02 +00001123 s->irq = irq;
bellard1d14ffa2005-10-30 18:58:22 +00001124 }
bellardd75d9f62004-10-09 17:20:54 +00001125 }
1126 break;
1127
bellardd75d9f62004-10-09 17:20:54 +00001128 case 0x81:
bellard85571bc2004-11-07 18:04:02 +00001129 {
1130 int dma, hdma;
1131
malc057fa652009-09-12 02:39:29 +04001132 dma = ctz32 (val & 0xf);
1133 hdma = ctz32 (val & 0xf0);
bellard1d14ffa2005-10-30 18:58:22 +00001134 if (dma != s->dma || hdma != s->hdma) {
John Arbuckle8ec660b2018-02-01 12:27:44 -05001135 qemu_log_mask(LOG_GUEST_ERROR, "attempt to change DMA 8bit"
1136 " %d(%d), 16bit %d(%d) (val=%#x)\n", dma, s->dma,
1137 hdma, s->hdma, val);
bellard1d14ffa2005-10-30 18:58:22 +00001138 }
bellard85571bc2004-11-07 18:04:02 +00001139#if 0
1140 s->dma = dma;
1141 s->hdma = hdma;
1142#endif
1143 }
bellardd75d9f62004-10-09 17:20:54 +00001144 break;
bellard85571bc2004-11-07 18:04:02 +00001145
1146 case 0x82:
John Arbuckle8ec660b2018-02-01 12:27:44 -05001147 qemu_log_mask(LOG_GUEST_ERROR, "attempt to write into IRQ status"
1148 " register (val=%#x)\n", val);
bellard202a4562004-04-16 22:09:02 +00001149 return;
bellard85571bc2004-11-07 18:04:02 +00001150
1151 default:
bellard1d14ffa2005-10-30 18:58:22 +00001152 if (s->mixer_nreg >= 0x80) {
1153 ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
1154 }
bellard85571bc2004-11-07 18:04:02 +00001155 break;
bellardd75d9f62004-10-09 17:20:54 +00001156 }
bellard27503322003-11-13 01:46:15 +00001157
bellard85571bc2004-11-07 18:04:02 +00001158 s->mixer_regs[s->mixer_nreg] = val;
bellardd75d9f62004-10-09 17:20:54 +00001159}
1160
Nutan Shinde8307c292015-10-07 22:02:54 +05301161static uint32_t mixer_read(void *opaque, uint32_t nport)
bellard27503322003-11-13 01:46:15 +00001162{
bellard85571bc2004-11-07 18:04:02 +00001163 SB16State *s = opaque;
bellardc0fe3822005-11-05 18:55:28 +00001164
1165 (void) nport;
bellard15b61472004-11-14 16:02:09 +00001166#ifndef DEBUG_SB16_MOST
bellard1d14ffa2005-10-30 18:58:22 +00001167 if (s->mixer_nreg != 0x82) {
1168 ldebug ("mixer_read[%#x] -> %#x\n",
1169 s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
1170 }
1171#else
bellard85571bc2004-11-07 18:04:02 +00001172 ldebug ("mixer_read[%#x] -> %#x\n",
1173 s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
bellard1d14ffa2005-10-30 18:58:22 +00001174#endif
bellard85571bc2004-11-07 18:04:02 +00001175 return s->mixer_regs[s->mixer_nreg];
bellard27503322003-11-13 01:46:15 +00001176}
1177
bellard85571bc2004-11-07 18:04:02 +00001178static int write_audio (SB16State *s, int nchan, int dma_pos,
1179 int dma_len, int len)
bellard27503322003-11-13 01:46:15 +00001180{
Hervé Poussineauf203c162016-02-03 11:28:58 -05001181 IsaDma *isa_dma = nchan == s->dma ? s->isa_dma : s->isa_hdma;
1182 IsaDmaClass *k = ISADMA_GET_CLASS(isa_dma);
bellard27503322003-11-13 01:46:15 +00001183 int temp, net;
bellardf9e92e92004-02-25 23:32:01 +00001184 uint8_t tmpbuf[4096];
bellard27503322003-11-13 01:46:15 +00001185
bellard85571bc2004-11-07 18:04:02 +00001186 temp = len;
bellard27503322003-11-13 01:46:15 +00001187 net = 0;
1188
1189 while (temp) {
bellard85571bc2004-11-07 18:04:02 +00001190 int left = dma_len - dma_pos;
bellardc0fe3822005-11-05 18:55:28 +00001191 int copied;
1192 size_t to_copy;
bellard27503322003-11-13 01:46:15 +00001193
Kővágó, Zoltán58935912019-08-19 01:06:54 +02001194 to_copy = MIN (temp, left);
bellardc0fe3822005-11-05 18:55:28 +00001195 if (to_copy > sizeof (tmpbuf)) {
1196 to_copy = sizeof (tmpbuf);
bellard1d14ffa2005-10-30 18:58:22 +00001197 }
bellard85571bc2004-11-07 18:04:02 +00001198
Hervé Poussineauf203c162016-02-03 11:28:58 -05001199 copied = k->read_memory(isa_dma, nchan, tmpbuf, dma_pos, to_copy);
bellard85571bc2004-11-07 18:04:02 +00001200 copied = AUD_write (s->voice, tmpbuf, copied);
bellard27503322003-11-13 01:46:15 +00001201
1202 temp -= copied;
bellard85571bc2004-11-07 18:04:02 +00001203 dma_pos = (dma_pos + copied) % dma_len;
bellard27503322003-11-13 01:46:15 +00001204 net += copied;
1205
bellard1d14ffa2005-10-30 18:58:22 +00001206 if (!copied) {
bellard85571bc2004-11-07 18:04:02 +00001207 break;
bellard1d14ffa2005-10-30 18:58:22 +00001208 }
bellard27503322003-11-13 01:46:15 +00001209 }
1210
1211 return net;
1212}
1213
bellard85571bc2004-11-07 18:04:02 +00001214static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
bellard27503322003-11-13 01:46:15 +00001215{
bellard85571bc2004-11-07 18:04:02 +00001216 SB16State *s = opaque;
bellard1d14ffa2005-10-30 18:58:22 +00001217 int till, copy, written, free;
bellard27503322003-11-13 01:46:15 +00001218
balrogca9cc282008-01-14 04:24:29 +00001219 if (s->block_size <= 0) {
John Arbuckle8ec660b2018-02-01 12:27:44 -05001220 qemu_log_mask(LOG_GUEST_ERROR, "invalid block size=%d nchan=%d"
1221 " dma_pos=%d dma_len=%d\n", s->block_size, nchan,
1222 dma_pos, dma_len);
balrogca9cc282008-01-14 04:24:29 +00001223 return dma_pos;
1224 }
1225
bellard85571bc2004-11-07 18:04:02 +00001226 if (s->left_till_irq < 0) {
1227 s->left_till_irq = s->block_size;
bellard27503322003-11-13 01:46:15 +00001228 }
1229
bellard1d14ffa2005-10-30 18:58:22 +00001230 if (s->voice) {
1231 free = s->audio_free & ~s->align;
1232 if ((free <= 0) || !dma_len) {
1233 return dma_pos;
1234 }
1235 }
1236 else {
1237 free = dma_len;
bellard27503322003-11-13 01:46:15 +00001238 }
1239
bellard85571bc2004-11-07 18:04:02 +00001240 copy = free;
1241 till = s->left_till_irq;
bellard27503322003-11-13 01:46:15 +00001242
bellardd75d9f62004-10-09 17:20:54 +00001243#ifdef DEBUG_SB16_MOST
bellard1d14ffa2005-10-30 18:58:22 +00001244 dolog ("pos:%06d %d till:%d len:%d\n",
1245 dma_pos, free, till, dma_len);
bellardd75d9f62004-10-09 17:20:54 +00001246#endif
1247
bellard27503322003-11-13 01:46:15 +00001248 if (till <= copy) {
Gonglei2ab5bf62014-08-11 21:00:53 +08001249 if (s->dma_auto == 0) {
bellard27503322003-11-13 01:46:15 +00001250 copy = till;
1251 }
1252 }
1253
bellard85571bc2004-11-07 18:04:02 +00001254 written = write_audio (s, nchan, dma_pos, dma_len, copy);
1255 dma_pos = (dma_pos + written) % dma_len;
1256 s->left_till_irq -= written;
bellard27503322003-11-13 01:46:15 +00001257
bellard85571bc2004-11-07 18:04:02 +00001258 if (s->left_till_irq <= 0) {
1259 s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
Jes Sorensen3a38d432009-08-14 11:36:15 +02001260 qemu_irq_raise (s->pic);
Gonglei2ab5bf62014-08-11 21:00:53 +08001261 if (s->dma_auto == 0) {
bellard85571bc2004-11-07 18:04:02 +00001262 control (s, 0);
1263 speaker (s, 0);
bellard27503322003-11-13 01:46:15 +00001264 }
1265 }
1266
bellardd75d9f62004-10-09 17:20:54 +00001267#ifdef DEBUG_SB16_MOST
bellard15b61472004-11-14 16:02:09 +00001268 ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
1269 dma_pos, free, dma_len, s->left_till_irq, copy, written,
1270 s->block_size);
bellardd75d9f62004-10-09 17:20:54 +00001271#endif
bellard27503322003-11-13 01:46:15 +00001272
bellard85571bc2004-11-07 18:04:02 +00001273 while (s->left_till_irq <= 0) {
1274 s->left_till_irq = s->block_size + s->left_till_irq;
bellard27503322003-11-13 01:46:15 +00001275 }
1276
bellard85571bc2004-11-07 18:04:02 +00001277 return dma_pos;
bellard27503322003-11-13 01:46:15 +00001278}
1279
bellard1d14ffa2005-10-30 18:58:22 +00001280static void SB_audio_callback (void *opaque, int free)
bellard27503322003-11-13 01:46:15 +00001281{
bellard85571bc2004-11-07 18:04:02 +00001282 SB16State *s = opaque;
bellard1d14ffa2005-10-30 18:58:22 +00001283 s->audio_free = free;
bellard27503322003-11-13 01:46:15 +00001284}
1285
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001286static int sb16_post_load (void *opaque, int version_id)
bellard27503322003-11-13 01:46:15 +00001287{
bellard85571bc2004-11-07 18:04:02 +00001288 SB16State *s = opaque;
bellard27503322003-11-13 01:46:15 +00001289
bellardfb065182004-11-09 23:09:44 +00001290 if (s->voice) {
bellardc0fe3822005-11-05 18:55:28 +00001291 AUD_close_out (&s->card, s->voice);
bellardfb065182004-11-09 23:09:44 +00001292 s->voice = NULL;
1293 }
bellard85571bc2004-11-07 18:04:02 +00001294
1295 if (s->dma_running) {
bellard1d14ffa2005-10-30 18:58:22 +00001296 if (s->freq) {
malc1ea879e2008-12-03 22:48:44 +00001297 struct audsettings as;
bellardc0fe3822005-11-05 18:55:28 +00001298
bellard1d14ffa2005-10-30 18:58:22 +00001299 s->audio_free = 0;
bellardc0fe3822005-11-05 18:55:28 +00001300
1301 as.freq = s->freq;
1302 as.nchannels = 1 << s->fmt_stereo;
1303 as.fmt = s->fmt;
bellardd929eba2006-07-04 21:47:22 +00001304 as.endianness = 0;
bellardc0fe3822005-11-05 18:55:28 +00001305
bellard1d14ffa2005-10-30 18:58:22 +00001306 s->voice = AUD_open_out (
bellardc0fe3822005-11-05 18:55:28 +00001307 &s->card,
bellard1d14ffa2005-10-30 18:58:22 +00001308 s->voice,
1309 "sb16",
1310 s,
1311 SB_audio_callback,
bellardd929eba2006-07-04 21:47:22 +00001312 &as
bellard1d14ffa2005-10-30 18:58:22 +00001313 );
1314 }
bellard85571bc2004-11-07 18:04:02 +00001315
1316 control (s, 1);
1317 speaker (s, s->speaker);
bellardd75d9f62004-10-09 17:20:54 +00001318 }
bellard85571bc2004-11-07 18:04:02 +00001319 return 0;
bellardd75d9f62004-10-09 17:20:54 +00001320}
bellardd75d9f62004-10-09 17:20:54 +00001321
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001322static const VMStateDescription vmstate_sb16 = {
1323 .name = "sb16",
1324 .version_id = 1,
1325 .minimum_version_id = 1,
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001326 .post_load = sb16_post_load,
Richard Henderson856a6fe2023-12-21 14:16:04 +11001327 .fields = (const VMStateField[]) {
Philippe Mathieu-Daudéfa293f82023-11-24 17:09:16 +01001328 VMSTATE_UNUSED( 4 /* irq */
1329 + 4 /* dma */
1330 + 4 /* hdma */
1331 + 4 /* port */
1332 + 4 /* ver */),
malccf4dc462012-02-07 22:11:04 +04001333 VMSTATE_INT32 (in_index, SB16State),
1334 VMSTATE_INT32 (out_data_len, SB16State),
1335 VMSTATE_INT32 (fmt_stereo, SB16State),
1336 VMSTATE_INT32 (fmt_signed, SB16State),
1337 VMSTATE_INT32 (fmt_bits, SB16State),
1338 VMSTATE_UINT32 (fmt, SB16State),
1339 VMSTATE_INT32 (dma_auto, SB16State),
1340 VMSTATE_INT32 (block_size, SB16State),
1341 VMSTATE_INT32 (fifo, SB16State),
1342 VMSTATE_INT32 (freq, SB16State),
1343 VMSTATE_INT32 (time_const, SB16State),
1344 VMSTATE_INT32 (speaker, SB16State),
1345 VMSTATE_INT32 (needed_bytes, SB16State),
1346 VMSTATE_INT32 (cmd, SB16State),
1347 VMSTATE_INT32 (use_hdma, SB16State),
1348 VMSTATE_INT32 (highspeed, SB16State),
1349 VMSTATE_INT32 (can_write, SB16State),
1350 VMSTATE_INT32 (v2x6, SB16State),
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001351
malccf4dc462012-02-07 22:11:04 +04001352 VMSTATE_UINT8 (csp_param, SB16State),
1353 VMSTATE_UINT8 (csp_value, SB16State),
1354 VMSTATE_UINT8 (csp_mode, SB16State),
1355 VMSTATE_UINT8 (csp_param, SB16State),
1356 VMSTATE_BUFFER (csp_regs, SB16State),
1357 VMSTATE_UINT8 (csp_index, SB16State),
1358 VMSTATE_BUFFER (csp_reg83, SB16State),
1359 VMSTATE_INT32 (csp_reg83r, SB16State),
1360 VMSTATE_INT32 (csp_reg83w, SB16State),
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001361
malccf4dc462012-02-07 22:11:04 +04001362 VMSTATE_BUFFER (in2_data, SB16State),
1363 VMSTATE_BUFFER (out_data, SB16State),
1364 VMSTATE_UINT8 (test_reg, SB16State),
1365 VMSTATE_UINT8 (last_read_byte, SB16State),
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001366
malccf4dc462012-02-07 22:11:04 +04001367 VMSTATE_INT32 (nzero, SB16State),
1368 VMSTATE_INT32 (left_till_irq, SB16State),
1369 VMSTATE_INT32 (dma_running, SB16State),
1370 VMSTATE_INT32 (bytes_per_second, SB16State),
1371 VMSTATE_INT32 (align, SB16State),
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001372
malccf4dc462012-02-07 22:11:04 +04001373 VMSTATE_INT32 (mixer_nreg, SB16State),
1374 VMSTATE_BUFFER (mixer_regs, SB16State),
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001375
malccf4dc462012-02-07 22:11:04 +04001376 VMSTATE_END_OF_LIST ()
Juan Quintelaebfd6f42009-12-02 11:49:35 +01001377 }
1378};
1379
Richard Henderson42c1a222011-08-15 16:10:47 -07001380static const MemoryRegionPortio sb16_ioport_list[] = {
1381 { 4, 1, 1, .write = mixer_write_indexb },
Richard Henderson42c1a222011-08-15 16:10:47 -07001382 { 5, 1, 1, .read = mixer_read, .write = mixer_write_datab },
1383 { 6, 1, 1, .read = dsp_read, .write = dsp_write },
1384 { 10, 1, 1, .read = dsp_read },
1385 { 12, 1, 1, .write = dsp_write },
1386 { 12, 4, 1, .read = dsp_read },
malccf4dc462012-02-07 22:11:04 +04001387 PORTIO_END_OF_LIST (),
Richard Henderson42c1a222011-08-15 16:10:47 -07001388};
1389
1390
Andreas Färberdb895a12012-11-25 02:37:14 +01001391static void sb16_initfn (Object *obj)
bellard27503322003-11-13 01:46:15 +00001392{
Andreas Färberdb895a12012-11-25 02:37:14 +01001393 SB16State *s = SB16 (obj);
bellardc0fe3822005-11-05 18:55:28 +00001394
bellard1d14ffa2005-10-30 18:58:22 +00001395 s->cmd = -1;
Andreas Färberdb895a12012-11-25 02:37:14 +01001396}
1397
1398static void sb16_realizefn (DeviceState *dev, Error **errp)
1399{
1400 ISADevice *isadev = ISA_DEVICE (dev);
Philippe Mathieu-Daudé8e7db8a2023-02-15 15:36:42 +01001401 ISABus *bus = isa_bus_from_device(isadev);
Andreas Färberdb895a12012-11-25 02:37:14 +01001402 SB16State *s = SB16 (dev);
Hervé Poussineauf203c162016-02-03 11:28:58 -05001403 IsaDmaClass *k;
Andreas Färberdb895a12012-11-25 02:37:14 +01001404
Martin Kletzandercb94ff52023-10-02 16:27:57 +02001405 if (!AUD_register_card ("sb16", &s->card, errp)) {
1406 return;
1407 }
1408
Philippe Mathieu-Daudé8e7db8a2023-02-15 15:36:42 +01001409 s->isa_hdma = isa_bus_get_dma(bus, s->hdma);
1410 s->isa_dma = isa_bus_get_dma(bus, s->dma);
Thomas Huthc9073232018-03-16 10:51:31 +01001411 if (!s->isa_dma || !s->isa_hdma) {
1412 error_setg(errp, "ISA controller does not support DMA");
1413 return;
1414 }
1415
Philippe Mathieu-Daudé8e7db8a2023-02-15 15:36:42 +01001416 s->pic = isa_bus_get_irq(bus, s->irq);
bellard27503322003-11-13 01:46:15 +00001417
bellard85571bc2004-11-07 18:04:02 +00001418 s->mixer_regs[0x80] = magic_of_irq (s->irq);
1419 s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
1420 s->mixer_regs[0x82] = 2 << 5;
1421
1422 s->csp_regs[5] = 1;
1423 s->csp_regs[9] = 0xf8;
1424
1425 reset_mixer (s);
Alex Blighbc72ad62013-08-21 16:03:08 +01001426 s->aux_ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, aux_timer, s);
bellard1d14ffa2005-10-30 18:58:22 +00001427 if (!s->aux_ts) {
John Arbuckle8ec660b2018-02-01 12:27:44 -05001428 error_setg(errp, "warning: Could not create auxiliary timer");
bellard1d14ffa2005-10-30 18:58:22 +00001429 }
bellard27503322003-11-13 01:46:15 +00001430
Marc-André Lureaue305a162016-07-13 02:11:59 +02001431 isa_register_portio_list(isadev, &s->portio_list, s->port,
1432 sb16_ioport_list, s, "sb16");
bellard85571bc2004-11-07 18:04:02 +00001433
Hervé Poussineauf203c162016-02-03 11:28:58 -05001434 k = ISADMA_GET_CLASS(s->isa_hdma);
1435 k->register_channel(s->isa_hdma, s->hdma, SB_read_DMA, s);
1436
Hervé Poussineauf203c162016-02-03 11:28:58 -05001437 k = ISADMA_GET_CLASS(s->isa_dma);
1438 k->register_channel(s->isa_dma, s->dma, SB_read_DMA, s);
1439
bellard85571bc2004-11-07 18:04:02 +00001440 s->can_write = 1;
bellard27503322003-11-13 01:46:15 +00001441}
Gerd Hoffmannf7b4f612009-09-10 11:43:30 +02001442
Anthony Liguori39bffca2011-12-07 21:34:16 -06001443static Property sb16_properties[] = {
Kővágó, Zoltán88e47b92019-08-19 01:06:49 +02001444 DEFINE_AUDIO_PROPERTIES(SB16State, card),
Paolo Bonzinic7bcc852014-02-08 11:01:53 +01001445 DEFINE_PROP_UINT32 ("version", SB16State, ver, 0x0405), /* 4.5 */
1446 DEFINE_PROP_UINT32 ("iobase", SB16State, port, 0x220),
Anthony Liguori39bffca2011-12-07 21:34:16 -06001447 DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5),
1448 DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1),
1449 DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5),
1450 DEFINE_PROP_END_OF_LIST (),
1451};
1452
malccf4dc462012-02-07 22:11:04 +04001453static void sb16_class_initfn (ObjectClass *klass, void *data)
Anthony Liguori8f04ee02011-12-04 11:52:49 -06001454{
malccf4dc462012-02-07 22:11:04 +04001455 DeviceClass *dc = DEVICE_CLASS (klass);
Andreas Färberdb895a12012-11-25 02:37:14 +01001456
1457 dc->realize = sb16_realizefn;
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +03001458 set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
Anthony Liguori39bffca2011-12-07 21:34:16 -06001459 dc->desc = "Creative Sound Blaster 16";
1460 dc->vmsd = &vmstate_sb16;
Marc-André Lureau4f67d302020-01-10 19:30:32 +04001461 device_class_set_props(dc, sb16_properties);
Anthony Liguori8f04ee02011-12-04 11:52:49 -06001462}
1463
Andreas Färber8c43a6f2013-01-10 16:19:07 +01001464static const TypeInfo sb16_info = {
Andreas Färber399f05a2013-04-27 22:18:49 +02001465 .name = TYPE_SB16,
Anthony Liguori39bffca2011-12-07 21:34:16 -06001466 .parent = TYPE_ISA_DEVICE,
1467 .instance_size = sizeof (SB16State),
Andreas Färberdb895a12012-11-25 02:37:14 +01001468 .instance_init = sb16_initfn,
Anthony Liguori39bffca2011-12-07 21:34:16 -06001469 .class_init = sb16_class_initfn,
Gerd Hoffmannf7b4f612009-09-10 11:43:30 +02001470};
1471
Andreas Färber83f7d432012-02-09 15:20:55 +01001472static void sb16_register_types (void)
Gerd Hoffmannf7b4f612009-09-10 11:43:30 +02001473{
malccf4dc462012-02-07 22:11:04 +04001474 type_register_static (&sb16_info);
Gerd Hoffmann4b961592020-07-02 15:25:14 +02001475 deprecated_register_soundhw("sb16", "Creative Sound Blaster 16",
1476 1, TYPE_SB16);
Gerd Hoffmannf7b4f612009-09-10 11:43:30 +02001477}
Andreas Färber83f7d432012-02-09 15:20:55 +01001478
1479type_init (sb16_register_types)