149ab747fSPaolo Bonzini /* 249ab747fSPaolo Bonzini * QEMU Soundblaster 16 emulation 349ab747fSPaolo Bonzini * 449ab747fSPaolo Bonzini * Copyright (c) 2003-2005 Vassili Karpov (malc) 549ab747fSPaolo Bonzini * 649ab747fSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 749ab747fSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 849ab747fSPaolo Bonzini * in the Software without restriction, including without limitation the rights 949ab747fSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1049ab747fSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 1149ab747fSPaolo Bonzini * furnished to do so, subject to the following conditions: 1249ab747fSPaolo Bonzini * 1349ab747fSPaolo Bonzini * The above copyright notice and this permission notice shall be included in 1449ab747fSPaolo Bonzini * all copies or substantial portions of the Software. 1549ab747fSPaolo Bonzini * 1649ab747fSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1749ab747fSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1849ab747fSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1949ab747fSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2049ab747fSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2149ab747fSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2249ab747fSPaolo Bonzini * THE SOFTWARE. 2349ab747fSPaolo Bonzini */ 2449ab747fSPaolo Bonzini #include "hw/hw.h" 2549ab747fSPaolo Bonzini #include "hw/audio/audio.h" 2649ab747fSPaolo Bonzini #include "audio/audio.h" 2749ab747fSPaolo Bonzini #include "hw/isa/isa.h" 2849ab747fSPaolo Bonzini #include "hw/qdev.h" 2949ab747fSPaolo Bonzini #include "qemu/timer.h" 3049ab747fSPaolo Bonzini #include "qemu/host-utils.h" 3149ab747fSPaolo Bonzini 3249ab747fSPaolo Bonzini #define dolog(...) AUD_log ("sb16", __VA_ARGS__) 3349ab747fSPaolo Bonzini 3449ab747fSPaolo Bonzini /* #define DEBUG */ 3549ab747fSPaolo Bonzini /* #define DEBUG_SB16_MOST */ 3649ab747fSPaolo Bonzini 3749ab747fSPaolo Bonzini #ifdef DEBUG 3849ab747fSPaolo Bonzini #define ldebug(...) dolog (__VA_ARGS__) 3949ab747fSPaolo Bonzini #else 4049ab747fSPaolo Bonzini #define ldebug(...) 4149ab747fSPaolo Bonzini #endif 4249ab747fSPaolo Bonzini 4349ab747fSPaolo Bonzini #define IO_READ_PROTO(name) \ 4449ab747fSPaolo Bonzini uint32_t name (void *opaque, uint32_t nport) 4549ab747fSPaolo Bonzini #define IO_WRITE_PROTO(name) \ 4649ab747fSPaolo Bonzini void name (void *opaque, uint32_t nport, uint32_t val) 4749ab747fSPaolo Bonzini 4849ab747fSPaolo Bonzini static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; 4949ab747fSPaolo Bonzini 50399f05a6SAndreas Färber #define TYPE_SB16 "sb16" 51399f05a6SAndreas Färber #define SB16(obj) OBJECT_CHECK (SB16State, (obj), TYPE_SB16) 52399f05a6SAndreas Färber 5349ab747fSPaolo Bonzini typedef struct SB16State { 54399f05a6SAndreas Färber ISADevice parent_obj; 55399f05a6SAndreas Färber 5649ab747fSPaolo Bonzini QEMUSoundCard card; 5749ab747fSPaolo Bonzini qemu_irq pic; 5849ab747fSPaolo Bonzini uint32_t irq; 5949ab747fSPaolo Bonzini uint32_t dma; 6049ab747fSPaolo Bonzini uint32_t hdma; 6149ab747fSPaolo Bonzini uint32_t port; 6249ab747fSPaolo Bonzini uint32_t ver; 6349ab747fSPaolo Bonzini 6449ab747fSPaolo Bonzini int in_index; 6549ab747fSPaolo Bonzini int out_data_len; 6649ab747fSPaolo Bonzini int fmt_stereo; 6749ab747fSPaolo Bonzini int fmt_signed; 6849ab747fSPaolo Bonzini int fmt_bits; 6949ab747fSPaolo Bonzini audfmt_e fmt; 7049ab747fSPaolo Bonzini int dma_auto; 7149ab747fSPaolo Bonzini int block_size; 7249ab747fSPaolo Bonzini int fifo; 7349ab747fSPaolo Bonzini int freq; 7449ab747fSPaolo Bonzini int time_const; 7549ab747fSPaolo Bonzini int speaker; 7649ab747fSPaolo Bonzini int needed_bytes; 7749ab747fSPaolo Bonzini int cmd; 7849ab747fSPaolo Bonzini int use_hdma; 7949ab747fSPaolo Bonzini int highspeed; 8049ab747fSPaolo Bonzini int can_write; 8149ab747fSPaolo Bonzini 8249ab747fSPaolo Bonzini int v2x6; 8349ab747fSPaolo Bonzini 8449ab747fSPaolo Bonzini uint8_t csp_param; 8549ab747fSPaolo Bonzini uint8_t csp_value; 8649ab747fSPaolo Bonzini uint8_t csp_mode; 8749ab747fSPaolo Bonzini uint8_t csp_regs[256]; 8849ab747fSPaolo Bonzini uint8_t csp_index; 8949ab747fSPaolo Bonzini uint8_t csp_reg83[4]; 9049ab747fSPaolo Bonzini int csp_reg83r; 9149ab747fSPaolo Bonzini int csp_reg83w; 9249ab747fSPaolo Bonzini 9349ab747fSPaolo Bonzini uint8_t in2_data[10]; 9449ab747fSPaolo Bonzini uint8_t out_data[50]; 9549ab747fSPaolo Bonzini uint8_t test_reg; 9649ab747fSPaolo Bonzini uint8_t last_read_byte; 9749ab747fSPaolo Bonzini int nzero; 9849ab747fSPaolo Bonzini 9949ab747fSPaolo Bonzini int left_till_irq; 10049ab747fSPaolo Bonzini 10149ab747fSPaolo Bonzini int dma_running; 10249ab747fSPaolo Bonzini int bytes_per_second; 10349ab747fSPaolo Bonzini int align; 10449ab747fSPaolo Bonzini int audio_free; 10549ab747fSPaolo Bonzini SWVoiceOut *voice; 10649ab747fSPaolo Bonzini 10749ab747fSPaolo Bonzini QEMUTimer *aux_ts; 10849ab747fSPaolo Bonzini /* mixer state */ 10949ab747fSPaolo Bonzini int mixer_nreg; 11049ab747fSPaolo Bonzini uint8_t mixer_regs[256]; 11149ab747fSPaolo Bonzini } SB16State; 11249ab747fSPaolo Bonzini 11349ab747fSPaolo Bonzini static void SB_audio_callback (void *opaque, int free); 11449ab747fSPaolo Bonzini 11549ab747fSPaolo Bonzini static int magic_of_irq (int irq) 11649ab747fSPaolo Bonzini { 11749ab747fSPaolo Bonzini switch (irq) { 11849ab747fSPaolo Bonzini case 5: 11949ab747fSPaolo Bonzini return 2; 12049ab747fSPaolo Bonzini case 7: 12149ab747fSPaolo Bonzini return 4; 12249ab747fSPaolo Bonzini case 9: 12349ab747fSPaolo Bonzini return 1; 12449ab747fSPaolo Bonzini case 10: 12549ab747fSPaolo Bonzini return 8; 12649ab747fSPaolo Bonzini default: 12749ab747fSPaolo Bonzini dolog ("bad irq %d\n", irq); 12849ab747fSPaolo Bonzini return 2; 12949ab747fSPaolo Bonzini } 13049ab747fSPaolo Bonzini } 13149ab747fSPaolo Bonzini 13249ab747fSPaolo Bonzini static int irq_of_magic (int magic) 13349ab747fSPaolo Bonzini { 13449ab747fSPaolo Bonzini switch (magic) { 13549ab747fSPaolo Bonzini case 1: 13649ab747fSPaolo Bonzini return 9; 13749ab747fSPaolo Bonzini case 2: 13849ab747fSPaolo Bonzini return 5; 13949ab747fSPaolo Bonzini case 4: 14049ab747fSPaolo Bonzini return 7; 14149ab747fSPaolo Bonzini case 8: 14249ab747fSPaolo Bonzini return 10; 14349ab747fSPaolo Bonzini default: 14449ab747fSPaolo Bonzini dolog ("bad irq magic %d\n", magic); 14549ab747fSPaolo Bonzini return -1; 14649ab747fSPaolo Bonzini } 14749ab747fSPaolo Bonzini } 14849ab747fSPaolo Bonzini 14949ab747fSPaolo Bonzini #if 0 15049ab747fSPaolo Bonzini static void log_dsp (SB16State *dsp) 15149ab747fSPaolo Bonzini { 15249ab747fSPaolo Bonzini ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n", 15349ab747fSPaolo Bonzini dsp->fmt_stereo ? "Stereo" : "Mono", 15449ab747fSPaolo Bonzini dsp->fmt_signed ? "Signed" : "Unsigned", 15549ab747fSPaolo Bonzini dsp->fmt_bits, 15649ab747fSPaolo Bonzini dsp->dma_auto ? "Auto" : "Single", 15749ab747fSPaolo Bonzini dsp->block_size, 15849ab747fSPaolo Bonzini dsp->freq, 15949ab747fSPaolo Bonzini dsp->time_const, 16049ab747fSPaolo Bonzini dsp->speaker); 16149ab747fSPaolo Bonzini } 16249ab747fSPaolo Bonzini #endif 16349ab747fSPaolo Bonzini 16449ab747fSPaolo Bonzini static void speaker (SB16State *s, int on) 16549ab747fSPaolo Bonzini { 16649ab747fSPaolo Bonzini s->speaker = on; 16749ab747fSPaolo Bonzini /* AUD_enable (s->voice, on); */ 16849ab747fSPaolo Bonzini } 16949ab747fSPaolo Bonzini 17049ab747fSPaolo Bonzini static void control (SB16State *s, int hold) 17149ab747fSPaolo Bonzini { 17249ab747fSPaolo Bonzini int dma = s->use_hdma ? s->hdma : s->dma; 17349ab747fSPaolo Bonzini s->dma_running = hold; 17449ab747fSPaolo Bonzini 17549ab747fSPaolo Bonzini ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma); 17649ab747fSPaolo Bonzini 17749ab747fSPaolo Bonzini if (hold) { 17849ab747fSPaolo Bonzini DMA_hold_DREQ (dma); 17949ab747fSPaolo Bonzini AUD_set_active_out (s->voice, 1); 18049ab747fSPaolo Bonzini } 18149ab747fSPaolo Bonzini else { 18249ab747fSPaolo Bonzini DMA_release_DREQ (dma); 18349ab747fSPaolo Bonzini AUD_set_active_out (s->voice, 0); 18449ab747fSPaolo Bonzini } 18549ab747fSPaolo Bonzini } 18649ab747fSPaolo Bonzini 18749ab747fSPaolo Bonzini static void aux_timer (void *opaque) 18849ab747fSPaolo Bonzini { 18949ab747fSPaolo Bonzini SB16State *s = opaque; 19049ab747fSPaolo Bonzini s->can_write = 1; 19149ab747fSPaolo Bonzini qemu_irq_raise (s->pic); 19249ab747fSPaolo Bonzini } 19349ab747fSPaolo Bonzini 19449ab747fSPaolo Bonzini #define DMA8_AUTO 1 19549ab747fSPaolo Bonzini #define DMA8_HIGH 2 19649ab747fSPaolo Bonzini 19749ab747fSPaolo Bonzini static void continue_dma8 (SB16State *s) 19849ab747fSPaolo Bonzini { 19949ab747fSPaolo Bonzini if (s->freq > 0) { 20049ab747fSPaolo Bonzini struct audsettings as; 20149ab747fSPaolo Bonzini 20249ab747fSPaolo Bonzini s->audio_free = 0; 20349ab747fSPaolo Bonzini 20449ab747fSPaolo Bonzini as.freq = s->freq; 20549ab747fSPaolo Bonzini as.nchannels = 1 << s->fmt_stereo; 20649ab747fSPaolo Bonzini as.fmt = s->fmt; 20749ab747fSPaolo Bonzini as.endianness = 0; 20849ab747fSPaolo Bonzini 20949ab747fSPaolo Bonzini s->voice = AUD_open_out ( 21049ab747fSPaolo Bonzini &s->card, 21149ab747fSPaolo Bonzini s->voice, 21249ab747fSPaolo Bonzini "sb16", 21349ab747fSPaolo Bonzini s, 21449ab747fSPaolo Bonzini SB_audio_callback, 21549ab747fSPaolo Bonzini &as 21649ab747fSPaolo Bonzini ); 21749ab747fSPaolo Bonzini } 21849ab747fSPaolo Bonzini 21949ab747fSPaolo Bonzini control (s, 1); 22049ab747fSPaolo Bonzini } 22149ab747fSPaolo Bonzini 22249ab747fSPaolo Bonzini static void dma_cmd8 (SB16State *s, int mask, int dma_len) 22349ab747fSPaolo Bonzini { 22449ab747fSPaolo Bonzini s->fmt = AUD_FMT_U8; 22549ab747fSPaolo Bonzini s->use_hdma = 0; 22649ab747fSPaolo Bonzini s->fmt_bits = 8; 22749ab747fSPaolo Bonzini s->fmt_signed = 0; 22849ab747fSPaolo Bonzini s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0; 22949ab747fSPaolo Bonzini if (-1 == s->time_const) { 23049ab747fSPaolo Bonzini if (s->freq <= 0) 23149ab747fSPaolo Bonzini s->freq = 11025; 23249ab747fSPaolo Bonzini } 23349ab747fSPaolo Bonzini else { 23449ab747fSPaolo Bonzini int tmp = (256 - s->time_const); 23549ab747fSPaolo Bonzini s->freq = (1000000 + (tmp / 2)) / tmp; 23649ab747fSPaolo Bonzini } 23749ab747fSPaolo Bonzini 23849ab747fSPaolo Bonzini if (dma_len != -1) { 23949ab747fSPaolo Bonzini s->block_size = dma_len << s->fmt_stereo; 24049ab747fSPaolo Bonzini } 24149ab747fSPaolo Bonzini else { 24249ab747fSPaolo Bonzini /* This is apparently the only way to make both Act1/PL 24349ab747fSPaolo Bonzini and SecondReality/FC work 24449ab747fSPaolo Bonzini 24549ab747fSPaolo Bonzini Act1 sets block size via command 0x48 and it's an odd number 24649ab747fSPaolo Bonzini SR does the same with even number 24749ab747fSPaolo Bonzini Both use stereo, and Creatives own documentation states that 24849ab747fSPaolo Bonzini 0x48 sets block size in bytes less one.. go figure */ 24949ab747fSPaolo Bonzini s->block_size &= ~s->fmt_stereo; 25049ab747fSPaolo Bonzini } 25149ab747fSPaolo Bonzini 25249ab747fSPaolo Bonzini s->freq >>= s->fmt_stereo; 25349ab747fSPaolo Bonzini s->left_till_irq = s->block_size; 25449ab747fSPaolo Bonzini s->bytes_per_second = (s->freq << s->fmt_stereo); 25549ab747fSPaolo Bonzini /* s->highspeed = (mask & DMA8_HIGH) != 0; */ 25649ab747fSPaolo Bonzini s->dma_auto = (mask & DMA8_AUTO) != 0; 25749ab747fSPaolo Bonzini s->align = (1 << s->fmt_stereo) - 1; 25849ab747fSPaolo Bonzini 25949ab747fSPaolo Bonzini if (s->block_size & s->align) { 26049ab747fSPaolo Bonzini dolog ("warning: misaligned block size %d, alignment %d\n", 26149ab747fSPaolo Bonzini s->block_size, s->align + 1); 26249ab747fSPaolo Bonzini } 26349ab747fSPaolo Bonzini 26449ab747fSPaolo Bonzini ldebug ("freq %d, stereo %d, sign %d, bits %d, " 26549ab747fSPaolo Bonzini "dma %d, auto %d, fifo %d, high %d\n", 26649ab747fSPaolo Bonzini s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, 26749ab747fSPaolo Bonzini s->block_size, s->dma_auto, s->fifo, s->highspeed); 26849ab747fSPaolo Bonzini 26949ab747fSPaolo Bonzini continue_dma8 (s); 27049ab747fSPaolo Bonzini speaker (s, 1); 27149ab747fSPaolo Bonzini } 27249ab747fSPaolo Bonzini 27349ab747fSPaolo Bonzini static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) 27449ab747fSPaolo Bonzini { 27549ab747fSPaolo Bonzini s->use_hdma = cmd < 0xc0; 27649ab747fSPaolo Bonzini s->fifo = (cmd >> 1) & 1; 27749ab747fSPaolo Bonzini s->dma_auto = (cmd >> 2) & 1; 27849ab747fSPaolo Bonzini s->fmt_signed = (d0 >> 4) & 1; 27949ab747fSPaolo Bonzini s->fmt_stereo = (d0 >> 5) & 1; 28049ab747fSPaolo Bonzini 28149ab747fSPaolo Bonzini switch (cmd >> 4) { 28249ab747fSPaolo Bonzini case 11: 28349ab747fSPaolo Bonzini s->fmt_bits = 16; 28449ab747fSPaolo Bonzini break; 28549ab747fSPaolo Bonzini 28649ab747fSPaolo Bonzini case 12: 28749ab747fSPaolo Bonzini s->fmt_bits = 8; 28849ab747fSPaolo Bonzini break; 28949ab747fSPaolo Bonzini } 29049ab747fSPaolo Bonzini 29149ab747fSPaolo Bonzini if (-1 != s->time_const) { 29249ab747fSPaolo Bonzini #if 1 29349ab747fSPaolo Bonzini int tmp = 256 - s->time_const; 29449ab747fSPaolo Bonzini s->freq = (1000000 + (tmp / 2)) / tmp; 29549ab747fSPaolo Bonzini #else 29649ab747fSPaolo Bonzini /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */ 29749ab747fSPaolo Bonzini s->freq = 1000000 / ((255 - s->time_const)); 29849ab747fSPaolo Bonzini #endif 29949ab747fSPaolo Bonzini s->time_const = -1; 30049ab747fSPaolo Bonzini } 30149ab747fSPaolo Bonzini 30249ab747fSPaolo Bonzini s->block_size = dma_len + 1; 30349ab747fSPaolo Bonzini s->block_size <<= (s->fmt_bits == 16); 30449ab747fSPaolo Bonzini if (!s->dma_auto) { 30549ab747fSPaolo Bonzini /* It is clear that for DOOM and auto-init this value 30649ab747fSPaolo Bonzini shouldn't take stereo into account, while Miles Sound Systems 30749ab747fSPaolo Bonzini setsound.exe with single transfer mode wouldn't work without it 30849ab747fSPaolo Bonzini wonders of SB16 yet again */ 30949ab747fSPaolo Bonzini s->block_size <<= s->fmt_stereo; 31049ab747fSPaolo Bonzini } 31149ab747fSPaolo Bonzini 31249ab747fSPaolo Bonzini ldebug ("freq %d, stereo %d, sign %d, bits %d, " 31349ab747fSPaolo Bonzini "dma %d, auto %d, fifo %d, high %d\n", 31449ab747fSPaolo Bonzini s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, 31549ab747fSPaolo Bonzini s->block_size, s->dma_auto, s->fifo, s->highspeed); 31649ab747fSPaolo Bonzini 31749ab747fSPaolo Bonzini if (16 == s->fmt_bits) { 31849ab747fSPaolo Bonzini if (s->fmt_signed) { 31949ab747fSPaolo Bonzini s->fmt = AUD_FMT_S16; 32049ab747fSPaolo Bonzini } 32149ab747fSPaolo Bonzini else { 32249ab747fSPaolo Bonzini s->fmt = AUD_FMT_U16; 32349ab747fSPaolo Bonzini } 32449ab747fSPaolo Bonzini } 32549ab747fSPaolo Bonzini else { 32649ab747fSPaolo Bonzini if (s->fmt_signed) { 32749ab747fSPaolo Bonzini s->fmt = AUD_FMT_S8; 32849ab747fSPaolo Bonzini } 32949ab747fSPaolo Bonzini else { 33049ab747fSPaolo Bonzini s->fmt = AUD_FMT_U8; 33149ab747fSPaolo Bonzini } 33249ab747fSPaolo Bonzini } 33349ab747fSPaolo Bonzini 33449ab747fSPaolo Bonzini s->left_till_irq = s->block_size; 33549ab747fSPaolo Bonzini 33649ab747fSPaolo Bonzini s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16); 33749ab747fSPaolo Bonzini s->highspeed = 0; 33849ab747fSPaolo Bonzini s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1; 33949ab747fSPaolo Bonzini if (s->block_size & s->align) { 34049ab747fSPaolo Bonzini dolog ("warning: misaligned block size %d, alignment %d\n", 34149ab747fSPaolo Bonzini s->block_size, s->align + 1); 34249ab747fSPaolo Bonzini } 34349ab747fSPaolo Bonzini 34449ab747fSPaolo Bonzini if (s->freq) { 34549ab747fSPaolo Bonzini struct audsettings as; 34649ab747fSPaolo Bonzini 34749ab747fSPaolo Bonzini s->audio_free = 0; 34849ab747fSPaolo Bonzini 34949ab747fSPaolo Bonzini as.freq = s->freq; 35049ab747fSPaolo Bonzini as.nchannels = 1 << s->fmt_stereo; 35149ab747fSPaolo Bonzini as.fmt = s->fmt; 35249ab747fSPaolo Bonzini as.endianness = 0; 35349ab747fSPaolo Bonzini 35449ab747fSPaolo Bonzini s->voice = AUD_open_out ( 35549ab747fSPaolo Bonzini &s->card, 35649ab747fSPaolo Bonzini s->voice, 35749ab747fSPaolo Bonzini "sb16", 35849ab747fSPaolo Bonzini s, 35949ab747fSPaolo Bonzini SB_audio_callback, 36049ab747fSPaolo Bonzini &as 36149ab747fSPaolo Bonzini ); 36249ab747fSPaolo Bonzini } 36349ab747fSPaolo Bonzini 36449ab747fSPaolo Bonzini control (s, 1); 36549ab747fSPaolo Bonzini speaker (s, 1); 36649ab747fSPaolo Bonzini } 36749ab747fSPaolo Bonzini 36849ab747fSPaolo Bonzini static inline void dsp_out_data (SB16State *s, uint8_t val) 36949ab747fSPaolo Bonzini { 37049ab747fSPaolo Bonzini ldebug ("outdata %#x\n", val); 37149ab747fSPaolo Bonzini if ((size_t) s->out_data_len < sizeof (s->out_data)) { 37249ab747fSPaolo Bonzini s->out_data[s->out_data_len++] = val; 37349ab747fSPaolo Bonzini } 37449ab747fSPaolo Bonzini } 37549ab747fSPaolo Bonzini 37649ab747fSPaolo Bonzini static inline uint8_t dsp_get_data (SB16State *s) 37749ab747fSPaolo Bonzini { 37849ab747fSPaolo Bonzini if (s->in_index) { 37949ab747fSPaolo Bonzini return s->in2_data[--s->in_index]; 38049ab747fSPaolo Bonzini } 38149ab747fSPaolo Bonzini else { 38249ab747fSPaolo Bonzini dolog ("buffer underflow\n"); 38349ab747fSPaolo Bonzini return 0; 38449ab747fSPaolo Bonzini } 38549ab747fSPaolo Bonzini } 38649ab747fSPaolo Bonzini 38749ab747fSPaolo Bonzini static void command (SB16State *s, uint8_t cmd) 38849ab747fSPaolo Bonzini { 38949ab747fSPaolo Bonzini ldebug ("command %#x\n", cmd); 39049ab747fSPaolo Bonzini 39149ab747fSPaolo Bonzini if (cmd > 0xaf && cmd < 0xd0) { 39249ab747fSPaolo Bonzini if (cmd & 8) { 39349ab747fSPaolo Bonzini dolog ("ADC not yet supported (command %#x)\n", cmd); 39449ab747fSPaolo Bonzini } 39549ab747fSPaolo Bonzini 39649ab747fSPaolo Bonzini switch (cmd >> 4) { 39749ab747fSPaolo Bonzini case 11: 39849ab747fSPaolo Bonzini case 12: 39949ab747fSPaolo Bonzini break; 40049ab747fSPaolo Bonzini default: 40149ab747fSPaolo Bonzini dolog ("%#x wrong bits\n", cmd); 40249ab747fSPaolo Bonzini } 40349ab747fSPaolo Bonzini s->needed_bytes = 3; 40449ab747fSPaolo Bonzini } 40549ab747fSPaolo Bonzini else { 40649ab747fSPaolo Bonzini s->needed_bytes = 0; 40749ab747fSPaolo Bonzini 40849ab747fSPaolo Bonzini switch (cmd) { 40949ab747fSPaolo Bonzini case 0x03: 41049ab747fSPaolo Bonzini dsp_out_data (s, 0x10); /* s->csp_param); */ 41149ab747fSPaolo Bonzini goto warn; 41249ab747fSPaolo Bonzini 41349ab747fSPaolo Bonzini case 0x04: 41449ab747fSPaolo Bonzini s->needed_bytes = 1; 41549ab747fSPaolo Bonzini goto warn; 41649ab747fSPaolo Bonzini 41749ab747fSPaolo Bonzini case 0x05: 41849ab747fSPaolo Bonzini s->needed_bytes = 2; 41949ab747fSPaolo Bonzini goto warn; 42049ab747fSPaolo Bonzini 42149ab747fSPaolo Bonzini case 0x08: 42249ab747fSPaolo Bonzini /* __asm__ ("int3"); */ 42349ab747fSPaolo Bonzini goto warn; 42449ab747fSPaolo Bonzini 42549ab747fSPaolo Bonzini case 0x0e: 42649ab747fSPaolo Bonzini s->needed_bytes = 2; 42749ab747fSPaolo Bonzini goto warn; 42849ab747fSPaolo Bonzini 42949ab747fSPaolo Bonzini case 0x09: 43049ab747fSPaolo Bonzini dsp_out_data (s, 0xf8); 43149ab747fSPaolo Bonzini goto warn; 43249ab747fSPaolo Bonzini 43349ab747fSPaolo Bonzini case 0x0f: 43449ab747fSPaolo Bonzini s->needed_bytes = 1; 43549ab747fSPaolo Bonzini goto warn; 43649ab747fSPaolo Bonzini 43749ab747fSPaolo Bonzini case 0x10: 43849ab747fSPaolo Bonzini s->needed_bytes = 1; 43949ab747fSPaolo Bonzini goto warn; 44049ab747fSPaolo Bonzini 44149ab747fSPaolo Bonzini case 0x14: 44249ab747fSPaolo Bonzini s->needed_bytes = 2; 44349ab747fSPaolo Bonzini s->block_size = 0; 44449ab747fSPaolo Bonzini break; 44549ab747fSPaolo Bonzini 44649ab747fSPaolo Bonzini case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */ 44749ab747fSPaolo Bonzini dma_cmd8 (s, DMA8_AUTO, -1); 44849ab747fSPaolo Bonzini break; 44949ab747fSPaolo Bonzini 45049ab747fSPaolo Bonzini case 0x20: /* Direct ADC, Juice/PL */ 45149ab747fSPaolo Bonzini dsp_out_data (s, 0xff); 45249ab747fSPaolo Bonzini goto warn; 45349ab747fSPaolo Bonzini 45449ab747fSPaolo Bonzini case 0x35: 45549ab747fSPaolo Bonzini dolog ("0x35 - MIDI command not implemented\n"); 45649ab747fSPaolo Bonzini break; 45749ab747fSPaolo Bonzini 45849ab747fSPaolo Bonzini case 0x40: 45949ab747fSPaolo Bonzini s->freq = -1; 46049ab747fSPaolo Bonzini s->time_const = -1; 46149ab747fSPaolo Bonzini s->needed_bytes = 1; 46249ab747fSPaolo Bonzini break; 46349ab747fSPaolo Bonzini 46449ab747fSPaolo Bonzini case 0x41: 46549ab747fSPaolo Bonzini s->freq = -1; 46649ab747fSPaolo Bonzini s->time_const = -1; 46749ab747fSPaolo Bonzini s->needed_bytes = 2; 46849ab747fSPaolo Bonzini break; 46949ab747fSPaolo Bonzini 47049ab747fSPaolo Bonzini case 0x42: 47149ab747fSPaolo Bonzini s->freq = -1; 47249ab747fSPaolo Bonzini s->time_const = -1; 47349ab747fSPaolo Bonzini s->needed_bytes = 2; 47449ab747fSPaolo Bonzini goto warn; 47549ab747fSPaolo Bonzini 47649ab747fSPaolo Bonzini case 0x45: 47749ab747fSPaolo Bonzini dsp_out_data (s, 0xaa); 47849ab747fSPaolo Bonzini goto warn; 47949ab747fSPaolo Bonzini 48049ab747fSPaolo Bonzini case 0x47: /* Continue Auto-Initialize DMA 16bit */ 48149ab747fSPaolo Bonzini break; 48249ab747fSPaolo Bonzini 48349ab747fSPaolo Bonzini case 0x48: 48449ab747fSPaolo Bonzini s->needed_bytes = 2; 48549ab747fSPaolo Bonzini break; 48649ab747fSPaolo Bonzini 48749ab747fSPaolo Bonzini case 0x74: 48849ab747fSPaolo Bonzini s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */ 48949ab747fSPaolo Bonzini dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n"); 49049ab747fSPaolo Bonzini break; 49149ab747fSPaolo Bonzini 49249ab747fSPaolo Bonzini case 0x75: /* DMA DAC, 4-bit ADPCM Reference */ 49349ab747fSPaolo Bonzini s->needed_bytes = 2; 49449ab747fSPaolo Bonzini dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n"); 49549ab747fSPaolo Bonzini break; 49649ab747fSPaolo Bonzini 49749ab747fSPaolo Bonzini case 0x76: /* DMA DAC, 2.6-bit ADPCM */ 49849ab747fSPaolo Bonzini s->needed_bytes = 2; 49949ab747fSPaolo Bonzini dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n"); 50049ab747fSPaolo Bonzini break; 50149ab747fSPaolo Bonzini 50249ab747fSPaolo Bonzini case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */ 50349ab747fSPaolo Bonzini s->needed_bytes = 2; 50449ab747fSPaolo Bonzini dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n"); 50549ab747fSPaolo Bonzini break; 50649ab747fSPaolo Bonzini 50749ab747fSPaolo Bonzini case 0x7d: 50849ab747fSPaolo Bonzini dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n"); 50949ab747fSPaolo Bonzini dolog ("not implemented\n"); 51049ab747fSPaolo Bonzini break; 51149ab747fSPaolo Bonzini 51249ab747fSPaolo Bonzini case 0x7f: 51349ab747fSPaolo Bonzini dolog ( 51449ab747fSPaolo Bonzini "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n" 51549ab747fSPaolo Bonzini ); 51649ab747fSPaolo Bonzini dolog ("not implemented\n"); 51749ab747fSPaolo Bonzini break; 51849ab747fSPaolo Bonzini 51949ab747fSPaolo Bonzini case 0x80: 52049ab747fSPaolo Bonzini s->needed_bytes = 2; 52149ab747fSPaolo Bonzini break; 52249ab747fSPaolo Bonzini 52349ab747fSPaolo Bonzini case 0x90: 52449ab747fSPaolo Bonzini case 0x91: 52549ab747fSPaolo Bonzini dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1); 52649ab747fSPaolo Bonzini break; 52749ab747fSPaolo Bonzini 52849ab747fSPaolo Bonzini case 0xd0: /* halt DMA operation. 8bit */ 52949ab747fSPaolo Bonzini control (s, 0); 53049ab747fSPaolo Bonzini break; 53149ab747fSPaolo Bonzini 53249ab747fSPaolo Bonzini case 0xd1: /* speaker on */ 53349ab747fSPaolo Bonzini speaker (s, 1); 53449ab747fSPaolo Bonzini break; 53549ab747fSPaolo Bonzini 53649ab747fSPaolo Bonzini case 0xd3: /* speaker off */ 53749ab747fSPaolo Bonzini speaker (s, 0); 53849ab747fSPaolo Bonzini break; 53949ab747fSPaolo Bonzini 54049ab747fSPaolo Bonzini case 0xd4: /* continue DMA operation. 8bit */ 54149ab747fSPaolo Bonzini /* KQ6 (or maybe Sierras audblst.drv in general) resets 54249ab747fSPaolo Bonzini the frequency between halt/continue */ 54349ab747fSPaolo Bonzini continue_dma8 (s); 54449ab747fSPaolo Bonzini break; 54549ab747fSPaolo Bonzini 54649ab747fSPaolo Bonzini case 0xd5: /* halt DMA operation. 16bit */ 54749ab747fSPaolo Bonzini control (s, 0); 54849ab747fSPaolo Bonzini break; 54949ab747fSPaolo Bonzini 55049ab747fSPaolo Bonzini case 0xd6: /* continue DMA operation. 16bit */ 55149ab747fSPaolo Bonzini control (s, 1); 55249ab747fSPaolo Bonzini break; 55349ab747fSPaolo Bonzini 55449ab747fSPaolo Bonzini case 0xd9: /* exit auto-init DMA after this block. 16bit */ 55549ab747fSPaolo Bonzini s->dma_auto = 0; 55649ab747fSPaolo Bonzini break; 55749ab747fSPaolo Bonzini 55849ab747fSPaolo Bonzini case 0xda: /* exit auto-init DMA after this block. 8bit */ 55949ab747fSPaolo Bonzini s->dma_auto = 0; 56049ab747fSPaolo Bonzini break; 56149ab747fSPaolo Bonzini 56249ab747fSPaolo Bonzini case 0xe0: /* DSP identification */ 56349ab747fSPaolo Bonzini s->needed_bytes = 1; 56449ab747fSPaolo Bonzini break; 56549ab747fSPaolo Bonzini 56649ab747fSPaolo Bonzini case 0xe1: 56749ab747fSPaolo Bonzini dsp_out_data (s, s->ver & 0xff); 56849ab747fSPaolo Bonzini dsp_out_data (s, s->ver >> 8); 56949ab747fSPaolo Bonzini break; 57049ab747fSPaolo Bonzini 57149ab747fSPaolo Bonzini case 0xe2: 57249ab747fSPaolo Bonzini s->needed_bytes = 1; 57349ab747fSPaolo Bonzini goto warn; 57449ab747fSPaolo Bonzini 57549ab747fSPaolo Bonzini case 0xe3: 57649ab747fSPaolo Bonzini { 57749ab747fSPaolo Bonzini int i; 57849ab747fSPaolo Bonzini for (i = sizeof (e3) - 1; i >= 0; --i) 57949ab747fSPaolo Bonzini dsp_out_data (s, e3[i]); 58049ab747fSPaolo Bonzini } 58149ab747fSPaolo Bonzini break; 58249ab747fSPaolo Bonzini 58349ab747fSPaolo Bonzini case 0xe4: /* write test reg */ 58449ab747fSPaolo Bonzini s->needed_bytes = 1; 58549ab747fSPaolo Bonzini break; 58649ab747fSPaolo Bonzini 58749ab747fSPaolo Bonzini case 0xe7: 58849ab747fSPaolo Bonzini dolog ("Attempt to probe for ESS (0xe7)?\n"); 58949ab747fSPaolo Bonzini break; 59049ab747fSPaolo Bonzini 59149ab747fSPaolo Bonzini case 0xe8: /* read test reg */ 59249ab747fSPaolo Bonzini dsp_out_data (s, s->test_reg); 59349ab747fSPaolo Bonzini break; 59449ab747fSPaolo Bonzini 59549ab747fSPaolo Bonzini case 0xf2: 59649ab747fSPaolo Bonzini case 0xf3: 59749ab747fSPaolo Bonzini dsp_out_data (s, 0xaa); 59849ab747fSPaolo Bonzini s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2; 59949ab747fSPaolo Bonzini qemu_irq_raise (s->pic); 60049ab747fSPaolo Bonzini break; 60149ab747fSPaolo Bonzini 60249ab747fSPaolo Bonzini case 0xf9: 60349ab747fSPaolo Bonzini s->needed_bytes = 1; 60449ab747fSPaolo Bonzini goto warn; 60549ab747fSPaolo Bonzini 60649ab747fSPaolo Bonzini case 0xfa: 60749ab747fSPaolo Bonzini dsp_out_data (s, 0); 60849ab747fSPaolo Bonzini goto warn; 60949ab747fSPaolo Bonzini 61049ab747fSPaolo Bonzini case 0xfc: /* FIXME */ 61149ab747fSPaolo Bonzini dsp_out_data (s, 0); 61249ab747fSPaolo Bonzini goto warn; 61349ab747fSPaolo Bonzini 61449ab747fSPaolo Bonzini default: 61549ab747fSPaolo Bonzini dolog ("Unrecognized command %#x\n", cmd); 61649ab747fSPaolo Bonzini break; 61749ab747fSPaolo Bonzini } 61849ab747fSPaolo Bonzini } 61949ab747fSPaolo Bonzini 62049ab747fSPaolo Bonzini if (!s->needed_bytes) { 62149ab747fSPaolo Bonzini ldebug ("\n"); 62249ab747fSPaolo Bonzini } 62349ab747fSPaolo Bonzini 62449ab747fSPaolo Bonzini exit: 62549ab747fSPaolo Bonzini if (!s->needed_bytes) { 62649ab747fSPaolo Bonzini s->cmd = -1; 62749ab747fSPaolo Bonzini } 62849ab747fSPaolo Bonzini else { 62949ab747fSPaolo Bonzini s->cmd = cmd; 63049ab747fSPaolo Bonzini } 63149ab747fSPaolo Bonzini return; 63249ab747fSPaolo Bonzini 63349ab747fSPaolo Bonzini warn: 63449ab747fSPaolo Bonzini dolog ("warning: command %#x,%d is not truly understood yet\n", 63549ab747fSPaolo Bonzini cmd, s->needed_bytes); 63649ab747fSPaolo Bonzini goto exit; 63749ab747fSPaolo Bonzini 63849ab747fSPaolo Bonzini } 63949ab747fSPaolo Bonzini 64049ab747fSPaolo Bonzini static uint16_t dsp_get_lohi (SB16State *s) 64149ab747fSPaolo Bonzini { 64249ab747fSPaolo Bonzini uint8_t hi = dsp_get_data (s); 64349ab747fSPaolo Bonzini uint8_t lo = dsp_get_data (s); 64449ab747fSPaolo Bonzini return (hi << 8) | lo; 64549ab747fSPaolo Bonzini } 64649ab747fSPaolo Bonzini 64749ab747fSPaolo Bonzini static uint16_t dsp_get_hilo (SB16State *s) 64849ab747fSPaolo Bonzini { 64949ab747fSPaolo Bonzini uint8_t lo = dsp_get_data (s); 65049ab747fSPaolo Bonzini uint8_t hi = dsp_get_data (s); 65149ab747fSPaolo Bonzini return (hi << 8) | lo; 65249ab747fSPaolo Bonzini } 65349ab747fSPaolo Bonzini 65449ab747fSPaolo Bonzini static void complete (SB16State *s) 65549ab747fSPaolo Bonzini { 65649ab747fSPaolo Bonzini int d0, d1, d2; 65749ab747fSPaolo Bonzini ldebug ("complete command %#x, in_index %d, needed_bytes %d\n", 65849ab747fSPaolo Bonzini s->cmd, s->in_index, s->needed_bytes); 65949ab747fSPaolo Bonzini 66049ab747fSPaolo Bonzini if (s->cmd > 0xaf && s->cmd < 0xd0) { 66149ab747fSPaolo Bonzini d2 = dsp_get_data (s); 66249ab747fSPaolo Bonzini d1 = dsp_get_data (s); 66349ab747fSPaolo Bonzini d0 = dsp_get_data (s); 66449ab747fSPaolo Bonzini 66549ab747fSPaolo Bonzini if (s->cmd & 8) { 66649ab747fSPaolo Bonzini dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", 66749ab747fSPaolo Bonzini s->cmd, d0, d1, d2); 66849ab747fSPaolo Bonzini } 66949ab747fSPaolo Bonzini else { 67049ab747fSPaolo Bonzini ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", 67149ab747fSPaolo Bonzini s->cmd, d0, d1, d2); 67249ab747fSPaolo Bonzini dma_cmd (s, s->cmd, d0, d1 + (d2 << 8)); 67349ab747fSPaolo Bonzini } 67449ab747fSPaolo Bonzini } 67549ab747fSPaolo Bonzini else { 67649ab747fSPaolo Bonzini switch (s->cmd) { 67749ab747fSPaolo Bonzini case 0x04: 67849ab747fSPaolo Bonzini s->csp_mode = dsp_get_data (s); 67949ab747fSPaolo Bonzini s->csp_reg83r = 0; 68049ab747fSPaolo Bonzini s->csp_reg83w = 0; 68149ab747fSPaolo Bonzini ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode); 68249ab747fSPaolo Bonzini break; 68349ab747fSPaolo Bonzini 68449ab747fSPaolo Bonzini case 0x05: 68549ab747fSPaolo Bonzini s->csp_param = dsp_get_data (s); 68649ab747fSPaolo Bonzini s->csp_value = dsp_get_data (s); 68749ab747fSPaolo Bonzini ldebug ("CSP command 0x05: param=%#x value=%#x\n", 68849ab747fSPaolo Bonzini s->csp_param, 68949ab747fSPaolo Bonzini s->csp_value); 69049ab747fSPaolo Bonzini break; 69149ab747fSPaolo Bonzini 69249ab747fSPaolo Bonzini case 0x0e: 69349ab747fSPaolo Bonzini d0 = dsp_get_data (s); 69449ab747fSPaolo Bonzini d1 = dsp_get_data (s); 69549ab747fSPaolo Bonzini ldebug ("write CSP register %d <- %#x\n", d1, d0); 69649ab747fSPaolo Bonzini if (d1 == 0x83) { 69749ab747fSPaolo Bonzini ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0); 69849ab747fSPaolo Bonzini s->csp_reg83[s->csp_reg83r % 4] = d0; 69949ab747fSPaolo Bonzini s->csp_reg83r += 1; 70049ab747fSPaolo Bonzini } 70149ab747fSPaolo Bonzini else { 70249ab747fSPaolo Bonzini s->csp_regs[d1] = d0; 70349ab747fSPaolo Bonzini } 70449ab747fSPaolo Bonzini break; 70549ab747fSPaolo Bonzini 70649ab747fSPaolo Bonzini case 0x0f: 70749ab747fSPaolo Bonzini d0 = dsp_get_data (s); 70849ab747fSPaolo Bonzini ldebug ("read CSP register %#x -> %#x, mode=%#x\n", 70949ab747fSPaolo Bonzini d0, s->csp_regs[d0], s->csp_mode); 71049ab747fSPaolo Bonzini if (d0 == 0x83) { 71149ab747fSPaolo Bonzini ldebug ("0x83[%d] -> %#x\n", 71249ab747fSPaolo Bonzini s->csp_reg83w, 71349ab747fSPaolo Bonzini s->csp_reg83[s->csp_reg83w % 4]); 71449ab747fSPaolo Bonzini dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]); 71549ab747fSPaolo Bonzini s->csp_reg83w += 1; 71649ab747fSPaolo Bonzini } 71749ab747fSPaolo Bonzini else { 71849ab747fSPaolo Bonzini dsp_out_data (s, s->csp_regs[d0]); 71949ab747fSPaolo Bonzini } 72049ab747fSPaolo Bonzini break; 72149ab747fSPaolo Bonzini 72249ab747fSPaolo Bonzini case 0x10: 72349ab747fSPaolo Bonzini d0 = dsp_get_data (s); 72449ab747fSPaolo Bonzini dolog ("cmd 0x10 d0=%#x\n", d0); 72549ab747fSPaolo Bonzini break; 72649ab747fSPaolo Bonzini 72749ab747fSPaolo Bonzini case 0x14: 72849ab747fSPaolo Bonzini dma_cmd8 (s, 0, dsp_get_lohi (s) + 1); 72949ab747fSPaolo Bonzini break; 73049ab747fSPaolo Bonzini 73149ab747fSPaolo Bonzini case 0x40: 73249ab747fSPaolo Bonzini s->time_const = dsp_get_data (s); 73349ab747fSPaolo Bonzini ldebug ("set time const %d\n", s->time_const); 73449ab747fSPaolo Bonzini break; 73549ab747fSPaolo Bonzini 73649ab747fSPaolo Bonzini case 0x42: /* FT2 sets output freq with this, go figure */ 73749ab747fSPaolo Bonzini #if 0 73849ab747fSPaolo Bonzini dolog ("cmd 0x42 might not do what it think it should\n"); 73949ab747fSPaolo Bonzini #endif 74049ab747fSPaolo Bonzini case 0x41: 74149ab747fSPaolo Bonzini s->freq = dsp_get_hilo (s); 74249ab747fSPaolo Bonzini ldebug ("set freq %d\n", s->freq); 74349ab747fSPaolo Bonzini break; 74449ab747fSPaolo Bonzini 74549ab747fSPaolo Bonzini case 0x48: 74649ab747fSPaolo Bonzini s->block_size = dsp_get_lohi (s) + 1; 74749ab747fSPaolo Bonzini ldebug ("set dma block len %d\n", s->block_size); 74849ab747fSPaolo Bonzini break; 74949ab747fSPaolo Bonzini 75049ab747fSPaolo Bonzini case 0x74: 75149ab747fSPaolo Bonzini case 0x75: 75249ab747fSPaolo Bonzini case 0x76: 75349ab747fSPaolo Bonzini case 0x77: 75449ab747fSPaolo Bonzini /* ADPCM stuff, ignore */ 75549ab747fSPaolo Bonzini break; 75649ab747fSPaolo Bonzini 75749ab747fSPaolo Bonzini case 0x80: 75849ab747fSPaolo Bonzini { 75949ab747fSPaolo Bonzini int freq, samples, bytes; 76049ab747fSPaolo Bonzini int64_t ticks; 76149ab747fSPaolo Bonzini 76249ab747fSPaolo Bonzini freq = s->freq > 0 ? s->freq : 11025; 76349ab747fSPaolo Bonzini samples = dsp_get_lohi (s) + 1; 76449ab747fSPaolo Bonzini bytes = samples << s->fmt_stereo << (s->fmt_bits == 16); 76549ab747fSPaolo Bonzini ticks = muldiv64 (bytes, get_ticks_per_sec (), freq); 76649ab747fSPaolo Bonzini if (ticks < get_ticks_per_sec () / 1024) { 76749ab747fSPaolo Bonzini qemu_irq_raise (s->pic); 76849ab747fSPaolo Bonzini } 76949ab747fSPaolo Bonzini else { 77049ab747fSPaolo Bonzini if (s->aux_ts) { 771*bc72ad67SAlex Bligh timer_mod ( 77249ab747fSPaolo Bonzini s->aux_ts, 773*bc72ad67SAlex Bligh qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks 77449ab747fSPaolo Bonzini ); 77549ab747fSPaolo Bonzini } 77649ab747fSPaolo Bonzini } 77749ab747fSPaolo Bonzini ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks); 77849ab747fSPaolo Bonzini } 77949ab747fSPaolo Bonzini break; 78049ab747fSPaolo Bonzini 78149ab747fSPaolo Bonzini case 0xe0: 78249ab747fSPaolo Bonzini d0 = dsp_get_data (s); 78349ab747fSPaolo Bonzini s->out_data_len = 0; 78449ab747fSPaolo Bonzini ldebug ("E0 data = %#x\n", d0); 78549ab747fSPaolo Bonzini dsp_out_data (s, ~d0); 78649ab747fSPaolo Bonzini break; 78749ab747fSPaolo Bonzini 78849ab747fSPaolo Bonzini case 0xe2: 78949ab747fSPaolo Bonzini #ifdef DEBUG 79049ab747fSPaolo Bonzini d0 = dsp_get_data (s); 79149ab747fSPaolo Bonzini dolog ("E2 = %#x\n", d0); 79249ab747fSPaolo Bonzini #endif 79349ab747fSPaolo Bonzini break; 79449ab747fSPaolo Bonzini 79549ab747fSPaolo Bonzini case 0xe4: 79649ab747fSPaolo Bonzini s->test_reg = dsp_get_data (s); 79749ab747fSPaolo Bonzini break; 79849ab747fSPaolo Bonzini 79949ab747fSPaolo Bonzini case 0xf9: 80049ab747fSPaolo Bonzini d0 = dsp_get_data (s); 80149ab747fSPaolo Bonzini ldebug ("command 0xf9 with %#x\n", d0); 80249ab747fSPaolo Bonzini switch (d0) { 80349ab747fSPaolo Bonzini case 0x0e: 80449ab747fSPaolo Bonzini dsp_out_data (s, 0xff); 80549ab747fSPaolo Bonzini break; 80649ab747fSPaolo Bonzini 80749ab747fSPaolo Bonzini case 0x0f: 80849ab747fSPaolo Bonzini dsp_out_data (s, 0x07); 80949ab747fSPaolo Bonzini break; 81049ab747fSPaolo Bonzini 81149ab747fSPaolo Bonzini case 0x37: 81249ab747fSPaolo Bonzini dsp_out_data (s, 0x38); 81349ab747fSPaolo Bonzini break; 81449ab747fSPaolo Bonzini 81549ab747fSPaolo Bonzini default: 81649ab747fSPaolo Bonzini dsp_out_data (s, 0x00); 81749ab747fSPaolo Bonzini break; 81849ab747fSPaolo Bonzini } 81949ab747fSPaolo Bonzini break; 82049ab747fSPaolo Bonzini 82149ab747fSPaolo Bonzini default: 82249ab747fSPaolo Bonzini dolog ("complete: unrecognized command %#x\n", s->cmd); 82349ab747fSPaolo Bonzini return; 82449ab747fSPaolo Bonzini } 82549ab747fSPaolo Bonzini } 82649ab747fSPaolo Bonzini 82749ab747fSPaolo Bonzini ldebug ("\n"); 82849ab747fSPaolo Bonzini s->cmd = -1; 82949ab747fSPaolo Bonzini } 83049ab747fSPaolo Bonzini 83149ab747fSPaolo Bonzini static void legacy_reset (SB16State *s) 83249ab747fSPaolo Bonzini { 83349ab747fSPaolo Bonzini struct audsettings as; 83449ab747fSPaolo Bonzini 83549ab747fSPaolo Bonzini s->freq = 11025; 83649ab747fSPaolo Bonzini s->fmt_signed = 0; 83749ab747fSPaolo Bonzini s->fmt_bits = 8; 83849ab747fSPaolo Bonzini s->fmt_stereo = 0; 83949ab747fSPaolo Bonzini 84049ab747fSPaolo Bonzini as.freq = s->freq; 84149ab747fSPaolo Bonzini as.nchannels = 1; 84249ab747fSPaolo Bonzini as.fmt = AUD_FMT_U8; 84349ab747fSPaolo Bonzini as.endianness = 0; 84449ab747fSPaolo Bonzini 84549ab747fSPaolo Bonzini s->voice = AUD_open_out ( 84649ab747fSPaolo Bonzini &s->card, 84749ab747fSPaolo Bonzini s->voice, 84849ab747fSPaolo Bonzini "sb16", 84949ab747fSPaolo Bonzini s, 85049ab747fSPaolo Bonzini SB_audio_callback, 85149ab747fSPaolo Bonzini &as 85249ab747fSPaolo Bonzini ); 85349ab747fSPaolo Bonzini 85449ab747fSPaolo Bonzini /* Not sure about that... */ 85549ab747fSPaolo Bonzini /* AUD_set_active_out (s->voice, 1); */ 85649ab747fSPaolo Bonzini } 85749ab747fSPaolo Bonzini 85849ab747fSPaolo Bonzini static void reset (SB16State *s) 85949ab747fSPaolo Bonzini { 86049ab747fSPaolo Bonzini qemu_irq_lower (s->pic); 86149ab747fSPaolo Bonzini if (s->dma_auto) { 86249ab747fSPaolo Bonzini qemu_irq_raise (s->pic); 86349ab747fSPaolo Bonzini qemu_irq_lower (s->pic); 86449ab747fSPaolo Bonzini } 86549ab747fSPaolo Bonzini 86649ab747fSPaolo Bonzini s->mixer_regs[0x82] = 0; 86749ab747fSPaolo Bonzini s->dma_auto = 0; 86849ab747fSPaolo Bonzini s->in_index = 0; 86949ab747fSPaolo Bonzini s->out_data_len = 0; 87049ab747fSPaolo Bonzini s->left_till_irq = 0; 87149ab747fSPaolo Bonzini s->needed_bytes = 0; 87249ab747fSPaolo Bonzini s->block_size = -1; 87349ab747fSPaolo Bonzini s->nzero = 0; 87449ab747fSPaolo Bonzini s->highspeed = 0; 87549ab747fSPaolo Bonzini s->v2x6 = 0; 87649ab747fSPaolo Bonzini s->cmd = -1; 87749ab747fSPaolo Bonzini 87849ab747fSPaolo Bonzini dsp_out_data (s, 0xaa); 87949ab747fSPaolo Bonzini speaker (s, 0); 88049ab747fSPaolo Bonzini control (s, 0); 88149ab747fSPaolo Bonzini legacy_reset (s); 88249ab747fSPaolo Bonzini } 88349ab747fSPaolo Bonzini 88449ab747fSPaolo Bonzini static IO_WRITE_PROTO (dsp_write) 88549ab747fSPaolo Bonzini { 88649ab747fSPaolo Bonzini SB16State *s = opaque; 88749ab747fSPaolo Bonzini int iport; 88849ab747fSPaolo Bonzini 88949ab747fSPaolo Bonzini iport = nport - s->port; 89049ab747fSPaolo Bonzini 89149ab747fSPaolo Bonzini ldebug ("write %#x <- %#x\n", nport, val); 89249ab747fSPaolo Bonzini switch (iport) { 89349ab747fSPaolo Bonzini case 0x06: 89449ab747fSPaolo Bonzini switch (val) { 89549ab747fSPaolo Bonzini case 0x00: 89649ab747fSPaolo Bonzini if (s->v2x6 == 1) { 89749ab747fSPaolo Bonzini reset (s); 89849ab747fSPaolo Bonzini } 89949ab747fSPaolo Bonzini s->v2x6 = 0; 90049ab747fSPaolo Bonzini break; 90149ab747fSPaolo Bonzini 90249ab747fSPaolo Bonzini case 0x01: 90349ab747fSPaolo Bonzini case 0x03: /* FreeBSD kludge */ 90449ab747fSPaolo Bonzini s->v2x6 = 1; 90549ab747fSPaolo Bonzini break; 90649ab747fSPaolo Bonzini 90749ab747fSPaolo Bonzini case 0xc6: 90849ab747fSPaolo Bonzini s->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */ 90949ab747fSPaolo Bonzini break; 91049ab747fSPaolo Bonzini 91149ab747fSPaolo Bonzini case 0xb8: /* Panic */ 91249ab747fSPaolo Bonzini reset (s); 91349ab747fSPaolo Bonzini break; 91449ab747fSPaolo Bonzini 91549ab747fSPaolo Bonzini case 0x39: 91649ab747fSPaolo Bonzini dsp_out_data (s, 0x38); 91749ab747fSPaolo Bonzini reset (s); 91849ab747fSPaolo Bonzini s->v2x6 = 0x39; 91949ab747fSPaolo Bonzini break; 92049ab747fSPaolo Bonzini 92149ab747fSPaolo Bonzini default: 92249ab747fSPaolo Bonzini s->v2x6 = val; 92349ab747fSPaolo Bonzini break; 92449ab747fSPaolo Bonzini } 92549ab747fSPaolo Bonzini break; 92649ab747fSPaolo Bonzini 92749ab747fSPaolo Bonzini case 0x0c: /* write data or command | write status */ 92849ab747fSPaolo Bonzini /* if (s->highspeed) */ 92949ab747fSPaolo Bonzini /* break; */ 93049ab747fSPaolo Bonzini 93149ab747fSPaolo Bonzini if (0 == s->needed_bytes) { 93249ab747fSPaolo Bonzini command (s, val); 93349ab747fSPaolo Bonzini #if 0 93449ab747fSPaolo Bonzini if (0 == s->needed_bytes) { 93549ab747fSPaolo Bonzini log_dsp (s); 93649ab747fSPaolo Bonzini } 93749ab747fSPaolo Bonzini #endif 93849ab747fSPaolo Bonzini } 93949ab747fSPaolo Bonzini else { 94049ab747fSPaolo Bonzini if (s->in_index == sizeof (s->in2_data)) { 94149ab747fSPaolo Bonzini dolog ("in data overrun\n"); 94249ab747fSPaolo Bonzini } 94349ab747fSPaolo Bonzini else { 94449ab747fSPaolo Bonzini s->in2_data[s->in_index++] = val; 94549ab747fSPaolo Bonzini if (s->in_index == s->needed_bytes) { 94649ab747fSPaolo Bonzini s->needed_bytes = 0; 94749ab747fSPaolo Bonzini complete (s); 94849ab747fSPaolo Bonzini #if 0 94949ab747fSPaolo Bonzini log_dsp (s); 95049ab747fSPaolo Bonzini #endif 95149ab747fSPaolo Bonzini } 95249ab747fSPaolo Bonzini } 95349ab747fSPaolo Bonzini } 95449ab747fSPaolo Bonzini break; 95549ab747fSPaolo Bonzini 95649ab747fSPaolo Bonzini default: 95749ab747fSPaolo Bonzini ldebug ("(nport=%#x, val=%#x)\n", nport, val); 95849ab747fSPaolo Bonzini break; 95949ab747fSPaolo Bonzini } 96049ab747fSPaolo Bonzini } 96149ab747fSPaolo Bonzini 96249ab747fSPaolo Bonzini static IO_READ_PROTO (dsp_read) 96349ab747fSPaolo Bonzini { 96449ab747fSPaolo Bonzini SB16State *s = opaque; 96549ab747fSPaolo Bonzini int iport, retval, ack = 0; 96649ab747fSPaolo Bonzini 96749ab747fSPaolo Bonzini iport = nport - s->port; 96849ab747fSPaolo Bonzini 96949ab747fSPaolo Bonzini switch (iport) { 97049ab747fSPaolo Bonzini case 0x06: /* reset */ 97149ab747fSPaolo Bonzini retval = 0xff; 97249ab747fSPaolo Bonzini break; 97349ab747fSPaolo Bonzini 97449ab747fSPaolo Bonzini case 0x0a: /* read data */ 97549ab747fSPaolo Bonzini if (s->out_data_len) { 97649ab747fSPaolo Bonzini retval = s->out_data[--s->out_data_len]; 97749ab747fSPaolo Bonzini s->last_read_byte = retval; 97849ab747fSPaolo Bonzini } 97949ab747fSPaolo Bonzini else { 98049ab747fSPaolo Bonzini if (s->cmd != -1) { 98149ab747fSPaolo Bonzini dolog ("empty output buffer for command %#x\n", 98249ab747fSPaolo Bonzini s->cmd); 98349ab747fSPaolo Bonzini } 98449ab747fSPaolo Bonzini retval = s->last_read_byte; 98549ab747fSPaolo Bonzini /* goto error; */ 98649ab747fSPaolo Bonzini } 98749ab747fSPaolo Bonzini break; 98849ab747fSPaolo Bonzini 98949ab747fSPaolo Bonzini case 0x0c: /* 0 can write */ 99049ab747fSPaolo Bonzini retval = s->can_write ? 0 : 0x80; 99149ab747fSPaolo Bonzini break; 99249ab747fSPaolo Bonzini 99349ab747fSPaolo Bonzini case 0x0d: /* timer interrupt clear */ 99449ab747fSPaolo Bonzini /* dolog ("timer interrupt clear\n"); */ 99549ab747fSPaolo Bonzini retval = 0; 99649ab747fSPaolo Bonzini break; 99749ab747fSPaolo Bonzini 99849ab747fSPaolo Bonzini case 0x0e: /* data available status | irq 8 ack */ 99949ab747fSPaolo Bonzini retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80; 100049ab747fSPaolo Bonzini if (s->mixer_regs[0x82] & 1) { 100149ab747fSPaolo Bonzini ack = 1; 100249ab747fSPaolo Bonzini s->mixer_regs[0x82] &= 1; 100349ab747fSPaolo Bonzini qemu_irq_lower (s->pic); 100449ab747fSPaolo Bonzini } 100549ab747fSPaolo Bonzini break; 100649ab747fSPaolo Bonzini 100749ab747fSPaolo Bonzini case 0x0f: /* irq 16 ack */ 100849ab747fSPaolo Bonzini retval = 0xff; 100949ab747fSPaolo Bonzini if (s->mixer_regs[0x82] & 2) { 101049ab747fSPaolo Bonzini ack = 1; 101149ab747fSPaolo Bonzini s->mixer_regs[0x82] &= 2; 101249ab747fSPaolo Bonzini qemu_irq_lower (s->pic); 101349ab747fSPaolo Bonzini } 101449ab747fSPaolo Bonzini break; 101549ab747fSPaolo Bonzini 101649ab747fSPaolo Bonzini default: 101749ab747fSPaolo Bonzini goto error; 101849ab747fSPaolo Bonzini } 101949ab747fSPaolo Bonzini 102049ab747fSPaolo Bonzini if (!ack) { 102149ab747fSPaolo Bonzini ldebug ("read %#x -> %#x\n", nport, retval); 102249ab747fSPaolo Bonzini } 102349ab747fSPaolo Bonzini 102449ab747fSPaolo Bonzini return retval; 102549ab747fSPaolo Bonzini 102649ab747fSPaolo Bonzini error: 102749ab747fSPaolo Bonzini dolog ("warning: dsp_read %#x error\n", nport); 102849ab747fSPaolo Bonzini return 0xff; 102949ab747fSPaolo Bonzini } 103049ab747fSPaolo Bonzini 103149ab747fSPaolo Bonzini static void reset_mixer (SB16State *s) 103249ab747fSPaolo Bonzini { 103349ab747fSPaolo Bonzini int i; 103449ab747fSPaolo Bonzini 103549ab747fSPaolo Bonzini memset (s->mixer_regs, 0xff, 0x7f); 103649ab747fSPaolo Bonzini memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83); 103749ab747fSPaolo Bonzini 103849ab747fSPaolo Bonzini s->mixer_regs[0x02] = 4; /* master volume 3bits */ 103949ab747fSPaolo Bonzini s->mixer_regs[0x06] = 4; /* MIDI volume 3bits */ 104049ab747fSPaolo Bonzini s->mixer_regs[0x08] = 0; /* CD volume 3bits */ 104149ab747fSPaolo Bonzini s->mixer_regs[0x0a] = 0; /* voice volume 2bits */ 104249ab747fSPaolo Bonzini 104349ab747fSPaolo Bonzini /* d5=input filt, d3=lowpass filt, d1,d2=input source */ 104449ab747fSPaolo Bonzini s->mixer_regs[0x0c] = 0; 104549ab747fSPaolo Bonzini 104649ab747fSPaolo Bonzini /* d5=output filt, d1=stereo switch */ 104749ab747fSPaolo Bonzini s->mixer_regs[0x0e] = 0; 104849ab747fSPaolo Bonzini 104949ab747fSPaolo Bonzini /* voice volume L d5,d7, R d1,d3 */ 105049ab747fSPaolo Bonzini s->mixer_regs[0x04] = (4 << 5) | (4 << 1); 105149ab747fSPaolo Bonzini /* master ... */ 105249ab747fSPaolo Bonzini s->mixer_regs[0x22] = (4 << 5) | (4 << 1); 105349ab747fSPaolo Bonzini /* MIDI ... */ 105449ab747fSPaolo Bonzini s->mixer_regs[0x26] = (4 << 5) | (4 << 1); 105549ab747fSPaolo Bonzini 105649ab747fSPaolo Bonzini for (i = 0x30; i < 0x48; i++) { 105749ab747fSPaolo Bonzini s->mixer_regs[i] = 0x20; 105849ab747fSPaolo Bonzini } 105949ab747fSPaolo Bonzini } 106049ab747fSPaolo Bonzini 106149ab747fSPaolo Bonzini static IO_WRITE_PROTO (mixer_write_indexb) 106249ab747fSPaolo Bonzini { 106349ab747fSPaolo Bonzini SB16State *s = opaque; 106449ab747fSPaolo Bonzini (void) nport; 106549ab747fSPaolo Bonzini s->mixer_nreg = val; 106649ab747fSPaolo Bonzini } 106749ab747fSPaolo Bonzini 106849ab747fSPaolo Bonzini static IO_WRITE_PROTO (mixer_write_datab) 106949ab747fSPaolo Bonzini { 107049ab747fSPaolo Bonzini SB16State *s = opaque; 107149ab747fSPaolo Bonzini 107249ab747fSPaolo Bonzini (void) nport; 107349ab747fSPaolo Bonzini ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val); 107449ab747fSPaolo Bonzini 107549ab747fSPaolo Bonzini switch (s->mixer_nreg) { 107649ab747fSPaolo Bonzini case 0x00: 107749ab747fSPaolo Bonzini reset_mixer (s); 107849ab747fSPaolo Bonzini break; 107949ab747fSPaolo Bonzini 108049ab747fSPaolo Bonzini case 0x80: 108149ab747fSPaolo Bonzini { 108249ab747fSPaolo Bonzini int irq = irq_of_magic (val); 108349ab747fSPaolo Bonzini ldebug ("setting irq to %d (val=%#x)\n", irq, val); 108449ab747fSPaolo Bonzini if (irq > 0) { 108549ab747fSPaolo Bonzini s->irq = irq; 108649ab747fSPaolo Bonzini } 108749ab747fSPaolo Bonzini } 108849ab747fSPaolo Bonzini break; 108949ab747fSPaolo Bonzini 109049ab747fSPaolo Bonzini case 0x81: 109149ab747fSPaolo Bonzini { 109249ab747fSPaolo Bonzini int dma, hdma; 109349ab747fSPaolo Bonzini 109449ab747fSPaolo Bonzini dma = ctz32 (val & 0xf); 109549ab747fSPaolo Bonzini hdma = ctz32 (val & 0xf0); 109649ab747fSPaolo Bonzini if (dma != s->dma || hdma != s->hdma) { 109749ab747fSPaolo Bonzini dolog ( 109849ab747fSPaolo Bonzini "attempt to change DMA " 109949ab747fSPaolo Bonzini "8bit %d(%d), 16bit %d(%d) (val=%#x)\n", 110049ab747fSPaolo Bonzini dma, s->dma, hdma, s->hdma, val); 110149ab747fSPaolo Bonzini } 110249ab747fSPaolo Bonzini #if 0 110349ab747fSPaolo Bonzini s->dma = dma; 110449ab747fSPaolo Bonzini s->hdma = hdma; 110549ab747fSPaolo Bonzini #endif 110649ab747fSPaolo Bonzini } 110749ab747fSPaolo Bonzini break; 110849ab747fSPaolo Bonzini 110949ab747fSPaolo Bonzini case 0x82: 111049ab747fSPaolo Bonzini dolog ("attempt to write into IRQ status register (val=%#x)\n", 111149ab747fSPaolo Bonzini val); 111249ab747fSPaolo Bonzini return; 111349ab747fSPaolo Bonzini 111449ab747fSPaolo Bonzini default: 111549ab747fSPaolo Bonzini if (s->mixer_nreg >= 0x80) { 111649ab747fSPaolo Bonzini ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val); 111749ab747fSPaolo Bonzini } 111849ab747fSPaolo Bonzini break; 111949ab747fSPaolo Bonzini } 112049ab747fSPaolo Bonzini 112149ab747fSPaolo Bonzini s->mixer_regs[s->mixer_nreg] = val; 112249ab747fSPaolo Bonzini } 112349ab747fSPaolo Bonzini 112449ab747fSPaolo Bonzini static IO_WRITE_PROTO (mixer_write_indexw) 112549ab747fSPaolo Bonzini { 112649ab747fSPaolo Bonzini mixer_write_indexb (opaque, nport, val & 0xff); 112749ab747fSPaolo Bonzini mixer_write_datab (opaque, nport, (val >> 8) & 0xff); 112849ab747fSPaolo Bonzini } 112949ab747fSPaolo Bonzini 113049ab747fSPaolo Bonzini static IO_READ_PROTO (mixer_read) 113149ab747fSPaolo Bonzini { 113249ab747fSPaolo Bonzini SB16State *s = opaque; 113349ab747fSPaolo Bonzini 113449ab747fSPaolo Bonzini (void) nport; 113549ab747fSPaolo Bonzini #ifndef DEBUG_SB16_MOST 113649ab747fSPaolo Bonzini if (s->mixer_nreg != 0x82) { 113749ab747fSPaolo Bonzini ldebug ("mixer_read[%#x] -> %#x\n", 113849ab747fSPaolo Bonzini s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); 113949ab747fSPaolo Bonzini } 114049ab747fSPaolo Bonzini #else 114149ab747fSPaolo Bonzini ldebug ("mixer_read[%#x] -> %#x\n", 114249ab747fSPaolo Bonzini s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); 114349ab747fSPaolo Bonzini #endif 114449ab747fSPaolo Bonzini return s->mixer_regs[s->mixer_nreg]; 114549ab747fSPaolo Bonzini } 114649ab747fSPaolo Bonzini 114749ab747fSPaolo Bonzini static int write_audio (SB16State *s, int nchan, int dma_pos, 114849ab747fSPaolo Bonzini int dma_len, int len) 114949ab747fSPaolo Bonzini { 115049ab747fSPaolo Bonzini int temp, net; 115149ab747fSPaolo Bonzini uint8_t tmpbuf[4096]; 115249ab747fSPaolo Bonzini 115349ab747fSPaolo Bonzini temp = len; 115449ab747fSPaolo Bonzini net = 0; 115549ab747fSPaolo Bonzini 115649ab747fSPaolo Bonzini while (temp) { 115749ab747fSPaolo Bonzini int left = dma_len - dma_pos; 115849ab747fSPaolo Bonzini int copied; 115949ab747fSPaolo Bonzini size_t to_copy; 116049ab747fSPaolo Bonzini 116149ab747fSPaolo Bonzini to_copy = audio_MIN (temp, left); 116249ab747fSPaolo Bonzini if (to_copy > sizeof (tmpbuf)) { 116349ab747fSPaolo Bonzini to_copy = sizeof (tmpbuf); 116449ab747fSPaolo Bonzini } 116549ab747fSPaolo Bonzini 116649ab747fSPaolo Bonzini copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy); 116749ab747fSPaolo Bonzini copied = AUD_write (s->voice, tmpbuf, copied); 116849ab747fSPaolo Bonzini 116949ab747fSPaolo Bonzini temp -= copied; 117049ab747fSPaolo Bonzini dma_pos = (dma_pos + copied) % dma_len; 117149ab747fSPaolo Bonzini net += copied; 117249ab747fSPaolo Bonzini 117349ab747fSPaolo Bonzini if (!copied) { 117449ab747fSPaolo Bonzini break; 117549ab747fSPaolo Bonzini } 117649ab747fSPaolo Bonzini } 117749ab747fSPaolo Bonzini 117849ab747fSPaolo Bonzini return net; 117949ab747fSPaolo Bonzini } 118049ab747fSPaolo Bonzini 118149ab747fSPaolo Bonzini static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) 118249ab747fSPaolo Bonzini { 118349ab747fSPaolo Bonzini SB16State *s = opaque; 118449ab747fSPaolo Bonzini int till, copy, written, free; 118549ab747fSPaolo Bonzini 118649ab747fSPaolo Bonzini if (s->block_size <= 0) { 118749ab747fSPaolo Bonzini dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n", 118849ab747fSPaolo Bonzini s->block_size, nchan, dma_pos, dma_len); 118949ab747fSPaolo Bonzini return dma_pos; 119049ab747fSPaolo Bonzini } 119149ab747fSPaolo Bonzini 119249ab747fSPaolo Bonzini if (s->left_till_irq < 0) { 119349ab747fSPaolo Bonzini s->left_till_irq = s->block_size; 119449ab747fSPaolo Bonzini } 119549ab747fSPaolo Bonzini 119649ab747fSPaolo Bonzini if (s->voice) { 119749ab747fSPaolo Bonzini free = s->audio_free & ~s->align; 119849ab747fSPaolo Bonzini if ((free <= 0) || !dma_len) { 119949ab747fSPaolo Bonzini return dma_pos; 120049ab747fSPaolo Bonzini } 120149ab747fSPaolo Bonzini } 120249ab747fSPaolo Bonzini else { 120349ab747fSPaolo Bonzini free = dma_len; 120449ab747fSPaolo Bonzini } 120549ab747fSPaolo Bonzini 120649ab747fSPaolo Bonzini copy = free; 120749ab747fSPaolo Bonzini till = s->left_till_irq; 120849ab747fSPaolo Bonzini 120949ab747fSPaolo Bonzini #ifdef DEBUG_SB16_MOST 121049ab747fSPaolo Bonzini dolog ("pos:%06d %d till:%d len:%d\n", 121149ab747fSPaolo Bonzini dma_pos, free, till, dma_len); 121249ab747fSPaolo Bonzini #endif 121349ab747fSPaolo Bonzini 121449ab747fSPaolo Bonzini if (till <= copy) { 121549ab747fSPaolo Bonzini if (0 == s->dma_auto) { 121649ab747fSPaolo Bonzini copy = till; 121749ab747fSPaolo Bonzini } 121849ab747fSPaolo Bonzini } 121949ab747fSPaolo Bonzini 122049ab747fSPaolo Bonzini written = write_audio (s, nchan, dma_pos, dma_len, copy); 122149ab747fSPaolo Bonzini dma_pos = (dma_pos + written) % dma_len; 122249ab747fSPaolo Bonzini s->left_till_irq -= written; 122349ab747fSPaolo Bonzini 122449ab747fSPaolo Bonzini if (s->left_till_irq <= 0) { 122549ab747fSPaolo Bonzini s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1; 122649ab747fSPaolo Bonzini qemu_irq_raise (s->pic); 122749ab747fSPaolo Bonzini if (0 == s->dma_auto) { 122849ab747fSPaolo Bonzini control (s, 0); 122949ab747fSPaolo Bonzini speaker (s, 0); 123049ab747fSPaolo Bonzini } 123149ab747fSPaolo Bonzini } 123249ab747fSPaolo Bonzini 123349ab747fSPaolo Bonzini #ifdef DEBUG_SB16_MOST 123449ab747fSPaolo Bonzini ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n", 123549ab747fSPaolo Bonzini dma_pos, free, dma_len, s->left_till_irq, copy, written, 123649ab747fSPaolo Bonzini s->block_size); 123749ab747fSPaolo Bonzini #endif 123849ab747fSPaolo Bonzini 123949ab747fSPaolo Bonzini while (s->left_till_irq <= 0) { 124049ab747fSPaolo Bonzini s->left_till_irq = s->block_size + s->left_till_irq; 124149ab747fSPaolo Bonzini } 124249ab747fSPaolo Bonzini 124349ab747fSPaolo Bonzini return dma_pos; 124449ab747fSPaolo Bonzini } 124549ab747fSPaolo Bonzini 124649ab747fSPaolo Bonzini static void SB_audio_callback (void *opaque, int free) 124749ab747fSPaolo Bonzini { 124849ab747fSPaolo Bonzini SB16State *s = opaque; 124949ab747fSPaolo Bonzini s->audio_free = free; 125049ab747fSPaolo Bonzini } 125149ab747fSPaolo Bonzini 125249ab747fSPaolo Bonzini static int sb16_post_load (void *opaque, int version_id) 125349ab747fSPaolo Bonzini { 125449ab747fSPaolo Bonzini SB16State *s = opaque; 125549ab747fSPaolo Bonzini 125649ab747fSPaolo Bonzini if (s->voice) { 125749ab747fSPaolo Bonzini AUD_close_out (&s->card, s->voice); 125849ab747fSPaolo Bonzini s->voice = NULL; 125949ab747fSPaolo Bonzini } 126049ab747fSPaolo Bonzini 126149ab747fSPaolo Bonzini if (s->dma_running) { 126249ab747fSPaolo Bonzini if (s->freq) { 126349ab747fSPaolo Bonzini struct audsettings as; 126449ab747fSPaolo Bonzini 126549ab747fSPaolo Bonzini s->audio_free = 0; 126649ab747fSPaolo Bonzini 126749ab747fSPaolo Bonzini as.freq = s->freq; 126849ab747fSPaolo Bonzini as.nchannels = 1 << s->fmt_stereo; 126949ab747fSPaolo Bonzini as.fmt = s->fmt; 127049ab747fSPaolo Bonzini as.endianness = 0; 127149ab747fSPaolo Bonzini 127249ab747fSPaolo Bonzini s->voice = AUD_open_out ( 127349ab747fSPaolo Bonzini &s->card, 127449ab747fSPaolo Bonzini s->voice, 127549ab747fSPaolo Bonzini "sb16", 127649ab747fSPaolo Bonzini s, 127749ab747fSPaolo Bonzini SB_audio_callback, 127849ab747fSPaolo Bonzini &as 127949ab747fSPaolo Bonzini ); 128049ab747fSPaolo Bonzini } 128149ab747fSPaolo Bonzini 128249ab747fSPaolo Bonzini control (s, 1); 128349ab747fSPaolo Bonzini speaker (s, s->speaker); 128449ab747fSPaolo Bonzini } 128549ab747fSPaolo Bonzini return 0; 128649ab747fSPaolo Bonzini } 128749ab747fSPaolo Bonzini 128849ab747fSPaolo Bonzini static const VMStateDescription vmstate_sb16 = { 128949ab747fSPaolo Bonzini .name = "sb16", 129049ab747fSPaolo Bonzini .version_id = 1, 129149ab747fSPaolo Bonzini .minimum_version_id = 1, 129249ab747fSPaolo Bonzini .minimum_version_id_old = 1, 129349ab747fSPaolo Bonzini .post_load = sb16_post_load, 129449ab747fSPaolo Bonzini .fields = (VMStateField []) { 129549ab747fSPaolo Bonzini VMSTATE_UINT32 (irq, SB16State), 129649ab747fSPaolo Bonzini VMSTATE_UINT32 (dma, SB16State), 129749ab747fSPaolo Bonzini VMSTATE_UINT32 (hdma, SB16State), 129849ab747fSPaolo Bonzini VMSTATE_UINT32 (port, SB16State), 129949ab747fSPaolo Bonzini VMSTATE_UINT32 (ver, SB16State), 130049ab747fSPaolo Bonzini VMSTATE_INT32 (in_index, SB16State), 130149ab747fSPaolo Bonzini VMSTATE_INT32 (out_data_len, SB16State), 130249ab747fSPaolo Bonzini VMSTATE_INT32 (fmt_stereo, SB16State), 130349ab747fSPaolo Bonzini VMSTATE_INT32 (fmt_signed, SB16State), 130449ab747fSPaolo Bonzini VMSTATE_INT32 (fmt_bits, SB16State), 130549ab747fSPaolo Bonzini VMSTATE_UINT32 (fmt, SB16State), 130649ab747fSPaolo Bonzini VMSTATE_INT32 (dma_auto, SB16State), 130749ab747fSPaolo Bonzini VMSTATE_INT32 (block_size, SB16State), 130849ab747fSPaolo Bonzini VMSTATE_INT32 (fifo, SB16State), 130949ab747fSPaolo Bonzini VMSTATE_INT32 (freq, SB16State), 131049ab747fSPaolo Bonzini VMSTATE_INT32 (time_const, SB16State), 131149ab747fSPaolo Bonzini VMSTATE_INT32 (speaker, SB16State), 131249ab747fSPaolo Bonzini VMSTATE_INT32 (needed_bytes, SB16State), 131349ab747fSPaolo Bonzini VMSTATE_INT32 (cmd, SB16State), 131449ab747fSPaolo Bonzini VMSTATE_INT32 (use_hdma, SB16State), 131549ab747fSPaolo Bonzini VMSTATE_INT32 (highspeed, SB16State), 131649ab747fSPaolo Bonzini VMSTATE_INT32 (can_write, SB16State), 131749ab747fSPaolo Bonzini VMSTATE_INT32 (v2x6, SB16State), 131849ab747fSPaolo Bonzini 131949ab747fSPaolo Bonzini VMSTATE_UINT8 (csp_param, SB16State), 132049ab747fSPaolo Bonzini VMSTATE_UINT8 (csp_value, SB16State), 132149ab747fSPaolo Bonzini VMSTATE_UINT8 (csp_mode, SB16State), 132249ab747fSPaolo Bonzini VMSTATE_UINT8 (csp_param, SB16State), 132349ab747fSPaolo Bonzini VMSTATE_BUFFER (csp_regs, SB16State), 132449ab747fSPaolo Bonzini VMSTATE_UINT8 (csp_index, SB16State), 132549ab747fSPaolo Bonzini VMSTATE_BUFFER (csp_reg83, SB16State), 132649ab747fSPaolo Bonzini VMSTATE_INT32 (csp_reg83r, SB16State), 132749ab747fSPaolo Bonzini VMSTATE_INT32 (csp_reg83w, SB16State), 132849ab747fSPaolo Bonzini 132949ab747fSPaolo Bonzini VMSTATE_BUFFER (in2_data, SB16State), 133049ab747fSPaolo Bonzini VMSTATE_BUFFER (out_data, SB16State), 133149ab747fSPaolo Bonzini VMSTATE_UINT8 (test_reg, SB16State), 133249ab747fSPaolo Bonzini VMSTATE_UINT8 (last_read_byte, SB16State), 133349ab747fSPaolo Bonzini 133449ab747fSPaolo Bonzini VMSTATE_INT32 (nzero, SB16State), 133549ab747fSPaolo Bonzini VMSTATE_INT32 (left_till_irq, SB16State), 133649ab747fSPaolo Bonzini VMSTATE_INT32 (dma_running, SB16State), 133749ab747fSPaolo Bonzini VMSTATE_INT32 (bytes_per_second, SB16State), 133849ab747fSPaolo Bonzini VMSTATE_INT32 (align, SB16State), 133949ab747fSPaolo Bonzini 134049ab747fSPaolo Bonzini VMSTATE_INT32 (mixer_nreg, SB16State), 134149ab747fSPaolo Bonzini VMSTATE_BUFFER (mixer_regs, SB16State), 134249ab747fSPaolo Bonzini 134349ab747fSPaolo Bonzini VMSTATE_END_OF_LIST () 134449ab747fSPaolo Bonzini } 134549ab747fSPaolo Bonzini }; 134649ab747fSPaolo Bonzini 134749ab747fSPaolo Bonzini static const MemoryRegionPortio sb16_ioport_list[] = { 134849ab747fSPaolo Bonzini { 4, 1, 1, .write = mixer_write_indexb }, 134949ab747fSPaolo Bonzini { 4, 1, 2, .write = mixer_write_indexw }, 135049ab747fSPaolo Bonzini { 5, 1, 1, .read = mixer_read, .write = mixer_write_datab }, 135149ab747fSPaolo Bonzini { 6, 1, 1, .read = dsp_read, .write = dsp_write }, 135249ab747fSPaolo Bonzini { 10, 1, 1, .read = dsp_read }, 135349ab747fSPaolo Bonzini { 12, 1, 1, .write = dsp_write }, 135449ab747fSPaolo Bonzini { 12, 4, 1, .read = dsp_read }, 135549ab747fSPaolo Bonzini PORTIO_END_OF_LIST (), 135649ab747fSPaolo Bonzini }; 135749ab747fSPaolo Bonzini 135849ab747fSPaolo Bonzini 1359db895a1eSAndreas Färber static void sb16_initfn (Object *obj) 136049ab747fSPaolo Bonzini { 1361db895a1eSAndreas Färber SB16State *s = SB16 (obj); 136249ab747fSPaolo Bonzini 136349ab747fSPaolo Bonzini s->cmd = -1; 1364db895a1eSAndreas Färber } 1365db895a1eSAndreas Färber 1366db895a1eSAndreas Färber static void sb16_realizefn (DeviceState *dev, Error **errp) 1367db895a1eSAndreas Färber { 1368db895a1eSAndreas Färber ISADevice *isadev = ISA_DEVICE (dev); 1369db895a1eSAndreas Färber SB16State *s = SB16 (dev); 1370db895a1eSAndreas Färber 1371db895a1eSAndreas Färber isa_init_irq (isadev, &s->pic, s->irq); 137249ab747fSPaolo Bonzini 137349ab747fSPaolo Bonzini s->mixer_regs[0x80] = magic_of_irq (s->irq); 137449ab747fSPaolo Bonzini s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma); 137549ab747fSPaolo Bonzini s->mixer_regs[0x82] = 2 << 5; 137649ab747fSPaolo Bonzini 137749ab747fSPaolo Bonzini s->csp_regs[5] = 1; 137849ab747fSPaolo Bonzini s->csp_regs[9] = 0xf8; 137949ab747fSPaolo Bonzini 138049ab747fSPaolo Bonzini reset_mixer (s); 1381*bc72ad67SAlex Bligh s->aux_ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, aux_timer, s); 138249ab747fSPaolo Bonzini if (!s->aux_ts) { 138349ab747fSPaolo Bonzini dolog ("warning: Could not create auxiliary timer\n"); 138449ab747fSPaolo Bonzini } 138549ab747fSPaolo Bonzini 1386db895a1eSAndreas Färber isa_register_portio_list (isadev, s->port, sb16_ioport_list, s, "sb16"); 138749ab747fSPaolo Bonzini 138849ab747fSPaolo Bonzini DMA_register_channel (s->hdma, SB_read_DMA, s); 138949ab747fSPaolo Bonzini DMA_register_channel (s->dma, SB_read_DMA, s); 139049ab747fSPaolo Bonzini s->can_write = 1; 139149ab747fSPaolo Bonzini 139249ab747fSPaolo Bonzini AUD_register_card ("sb16", &s->card); 139349ab747fSPaolo Bonzini } 139449ab747fSPaolo Bonzini 139536cd6f6fSPaolo Bonzini static int SB16_init (ISABus *bus) 139649ab747fSPaolo Bonzini { 1397399f05a6SAndreas Färber isa_create_simple (bus, TYPE_SB16); 139849ab747fSPaolo Bonzini return 0; 139949ab747fSPaolo Bonzini } 140049ab747fSPaolo Bonzini 140149ab747fSPaolo Bonzini static Property sb16_properties[] = { 140249ab747fSPaolo Bonzini DEFINE_PROP_HEX32 ("version", SB16State, ver, 0x0405), /* 4.5 */ 140349ab747fSPaolo Bonzini DEFINE_PROP_HEX32 ("iobase", SB16State, port, 0x220), 140449ab747fSPaolo Bonzini DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5), 140549ab747fSPaolo Bonzini DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1), 140649ab747fSPaolo Bonzini DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5), 140749ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST (), 140849ab747fSPaolo Bonzini }; 140949ab747fSPaolo Bonzini 141049ab747fSPaolo Bonzini static void sb16_class_initfn (ObjectClass *klass, void *data) 141149ab747fSPaolo Bonzini { 141249ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS (klass); 1413db895a1eSAndreas Färber 1414db895a1eSAndreas Färber dc->realize = sb16_realizefn; 1415125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_SOUND, dc->categories); 141649ab747fSPaolo Bonzini dc->desc = "Creative Sound Blaster 16"; 141749ab747fSPaolo Bonzini dc->vmsd = &vmstate_sb16; 141849ab747fSPaolo Bonzini dc->props = sb16_properties; 141949ab747fSPaolo Bonzini } 142049ab747fSPaolo Bonzini 142149ab747fSPaolo Bonzini static const TypeInfo sb16_info = { 1422399f05a6SAndreas Färber .name = TYPE_SB16, 142349ab747fSPaolo Bonzini .parent = TYPE_ISA_DEVICE, 142449ab747fSPaolo Bonzini .instance_size = sizeof (SB16State), 1425db895a1eSAndreas Färber .instance_init = sb16_initfn, 142649ab747fSPaolo Bonzini .class_init = sb16_class_initfn, 142749ab747fSPaolo Bonzini }; 142849ab747fSPaolo Bonzini 142949ab747fSPaolo Bonzini static void sb16_register_types (void) 143049ab747fSPaolo Bonzini { 143149ab747fSPaolo Bonzini type_register_static (&sb16_info); 143236cd6f6fSPaolo Bonzini isa_register_soundhw("sb16", "Creative Sound Blaster 16", SB16_init); 143349ab747fSPaolo Bonzini } 143449ab747fSPaolo Bonzini 143549ab747fSPaolo Bonzini type_init (sb16_register_types) 1436