Merge pull request #1581 from 86Box/master

Bring the branch up to par with master.
This commit is contained in:
Miran Grča
2021-08-04 09:15:08 +02:00
committed by GitHub
30 changed files with 2075 additions and 480 deletions

View File

@@ -14,7 +14,7 @@
#
add_library(snd OBJECT sound.c openal.c snd_opl.c snd_opl_nuked.c snd_resid.cc
midi.c midi_system.c snd_speaker.c snd_pssj.c snd_lpt_dac.c
midi.c midi_system.c snd_speaker.c snd_pssj.c snd_lpt_dac.c snd_ac97_codec.c snd_ac97_via.c
snd_lpt_dss.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c
snd_azt2316a.c snd_cms.c snd_cs423x.c snd_gus.c snd_sb.c snd_sb_dsp.c
snd_emu8k.c snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c)

394
src/sound/snd_ac97_codec.c Normal file
View File

@@ -0,0 +1,394 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* AC'97 audio codec emulation.
*
*
*
* Authors: RichardG, <richardg867@gmail.com>
*
* Copyright 2021 RichardG.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/snd_ac97.h>
#define AC97_VENDOR_ID(f, s, t, dev) ((((f) & 0xff) << 24) | (((s) & 0xff) << 16) | (((t) & 0xff) << 8) | ((dev) & 0xff))
enum {
AC97_CODEC_AD1881 = AC97_VENDOR_ID('A', 'D', 'S', 0x40),
AC97_CODEC_ALC100 = AC97_VENDOR_ID('A', 'L', 'C', 0x20),
AC97_CODEC_CS4297 = AC97_VENDOR_ID('C', 'R', 'Y', 0x03),
AC97_CODEC_CS4297A = AC97_VENDOR_ID('C', 'R', 'Y', 0x13),
AC97_CODEC_WM9701A = AC97_VENDOR_ID('W', 'M', 'L', 0x00)
};
#ifdef ENABLE_AC97_CODEC_LOG
int ac97_codec_do_log = ENABLE_AC97_CODEC_LOG;
static void
ac97_codec_log(const char *fmt, ...)
{
va_list ap;
if (ac97_codec_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define ac97_codec_log(fmt, ...)
#endif
static const int32_t codec_attn[] = {
25, 32, 41, 51, 65, 82, 103, 130, 164, 206, 260, 327, 412, 519, 653, 822,
1036, 1304, 1641, 2067, 2602, 3276, 4125, 5192, 6537, 8230, 10362, 13044, 16422, 20674, 26027, 32767,
41305, 52068, 65636, 82739, 104299, 131477, 165737, 208925
};
ac97_codec_t **ac97_codec = NULL, **ac97_modem_codec = NULL;
int ac97_codec_count = 0, ac97_modem_codec_count = 0,
ac97_codec_id = 0, ac97_modem_codec_id = 0;
uint8_t
ac97_codec_read(ac97_codec_t *dev, uint8_t reg)
{
uint8_t ret = dev->regs[reg & 0x7f];
ac97_codec_log("AC97 Codec %d: read(%02X) = %02X\n", dev->codec_id, reg, ret);
return ret;
}
void
ac97_codec_write(ac97_codec_t *dev, uint8_t reg, uint8_t val)
{
uint8_t i;
ac97_codec_log("AC97 Codec %d: write(%02X, %02X)\n", dev->codec_id, reg, val);
reg &= 0x7f;
switch (reg) {
case 0x00: case 0x01: /* Reset / ID code */
ac97_codec_reset(dev);
return;
case 0x08: case 0x09: /* Master Tone Control (optional) */
case 0x0d: /* Phone Volume MSB */
case 0x0f: /* Mic Volume MSB */
case 0x1e: case 0x1f: /* Record Gain Mic (optional) */
case 0x22: case 0x23: /* 3D Control (optional) */
case 0x24: case 0x25: /* Audio Interrupt and Paging Mechanism (optional) */
case 0x26: /* Powerdown Ctrl/Stat LSB */
case 0x28: case 0x29: /* Extended Audio ID */
case 0x2b: /* Extended Audio Status/Control MSB */
//case 0x36 ... 0x59: /* Linux tests for audio capability by writing to 38-39 */
case 0x5a ... 0x5f: /* Vendor Reserved */
//case 0x60 ... 0x6f:
case 0x70 ... 0x7f: /* Vendor Reserved */
/* Read-only registers. */
return;
case 0x02: /* Master Volume LSB */
case 0x04: /* Aux Out Volume LSB */
case 0x06: /* Mono Volume LSB */
val &= 0x3f;
/* fall-through */
case 0x03: /* Master Volume MSB */
case 0x05: /* Aux Out Volume MSB */
val &= 0xbf;
/* Limit level to a maximum of 011111. */
if (val & 0x20) {
val &= ~0x20;
val |= 0x1f;
}
break;
case 0x07: /* Mono Volume MSB */
case 0x0b: /* PC Beep Volume MSB */
case 0x20: /* General Purpose LSB */
val &= 0x80;
break;
case 0x0a: /* PC Beep Volume LSB */
val &= 0x1e;
break;
case 0x0c: /* Phone Volume LSB */
case 0x10: /* Line In Volume LSB */
case 0x12: /* CD Volume LSB */
case 0x14: /* Video Volume LSB */
case 0x16: /* Aux In Volume LSB */
case 0x18: /* PCM Out Volume LSB */
val &= 0x1f;
break;
case 0x0e: /* Mic Volume LSB */
val &= 0x5f;
break;
case 0x11: /* Line In Volume MSB */
case 0x13: /* CD Volume MSB */
case 0x15: /* Video Volume MSB */
case 0x17: /* Aux In Volume MSB */
case 0x19: /* PCM Out Volume MSB */
val &= 0x9f;
break;
case 0x1a: case 0x1b: /* Record Select */
val &= 0x07;
break;
case 0x1c: /* Record Gain LSB */
val &= 0x0f;
break;
case 0x1d: /* Record Gain MSB */
val &= 0x8f;
break;
case 0x21: /* General Purpose MSB */
val &= 0x83;
break;
case 0x2a: /* Extended Audio Status/Control LSB */
#ifdef AC97_CODEC_FULL_RATE_RANGE /* enable DRA (double rate) support */
val &= 0x0b;
#else
val &= 0x09;
#endif
/* Reset DAC sample rates to 48 KHz (96 KHz with DRA) if VRA is being cleared. */
if (!(val & 0x01)) {
for (i = 0x2c; i <= 0x30; i += 2)
*((uint16_t *) &dev->regs[i]) = 48000;
}
/* Reset ADC sample rates to 48 KHz if VRM is being cleared. */
if (!(val & 0x08)) {
for (i = 0x32; i <= 0x34; i += 2)
*((uint16_t *) &dev->regs[i]) = 48000;
}
break;
case 0x2c ... 0x35: /* DAC/ADC Rates */
/* Writable only if VRA/VRM is set. */
i = (reg >= 0x32) ? 0x08 : 0x01;
if (!(dev->regs[0x2a] & i))
return;
#ifndef AC97_CODEC_FULL_RATE_RANGE
/* Limit to 48 KHz on MSB write. */
if ((reg & 1) && (((val << 8) | dev->regs[reg & 0x7e]) > 48000)) {
*((uint16_t *) &dev->regs[reg & 0x7e]) = 48000;
return;
}
#endif
break;
}
dev->regs[reg] = val;
}
void
ac97_codec_reset(void *priv)
{
ac97_codec_t *dev = (ac97_codec_t *) priv;
uint8_t i;
ac97_codec_log("AC97 Codec %d: reset()\n", dev->codec_id);
memset(dev->regs, 0, sizeof(dev->regs));
/* Set default level and gain values. */
for (i = 0x02; i <= 0x18; i += 2) {
if (i == 0x08)
continue;
if (i >= 0x0c)
dev->regs[i] = 0x08;
dev->regs[i | 1] = (i >= 0x10) ? 0x88 : 0x80;
}
/* Flag codec as ready. */
dev->regs[0x26] = 0x0f;
/* Set up variable sample rate support. */
#ifdef AC97_CODEC_FULL_RATE_RANGE /* enable DRA (double rate) support */
dev->regs[0x28] = 0x0b;
#else
dev->regs[0x28] = 0x09;
#endif
ac97_codec_write(dev, 0x2a, 0x00); /* reset DAC/ADC sample rates */
/* Set codec and vendor IDs. */
dev->regs[0x29] = (dev->codec_id << 6) | 0x02;
dev->regs[0x7c] = dev->vendor_id >> 16;
dev->regs[0x7d] = dev->vendor_id >> 24;
dev->regs[0x7e] = dev->vendor_id;
dev->regs[0x7f] = dev->vendor_id >> 8;
}
void
ac97_codec_getattn(void *priv, uint8_t reg, int *l, int *r)
{
ac97_codec_t *dev = (ac97_codec_t *) priv;
uint8_t r_val = dev->regs[reg],
l_val = dev->regs[reg | 1];
if (l_val & 0x80) { /* mute */
*l = 0;
*r = 0;
return;
}
l_val &= 0x1f;
r_val &= 0x1f;
if (reg < 0x10) { /* 5-bit level (converted from 6-bit on register write) */
*l = codec_attn[0x1f - l_val];
*r = codec_attn[0x1f - r_val];
} else { /* 5-bit gain */
*l = codec_attn[0x27 - l_val];
*r = codec_attn[0x27 - r_val];
}
}
uint32_t
ac97_codec_getrate(void *priv, uint8_t reg)
{
ac97_codec_t *dev = (ac97_codec_t *) priv;
/* Get configured sample rate, which is always 48000 if VRA/VRM is not set. */
uint32_t ret = *((uint16_t *) &dev->regs[reg]);
#ifdef AC97_CODEC_FULL_RATE_RANGE
/* If this is a DAC, double sample rate if DRA is set. */
if ((reg < 0x32) && (dev->regs[0x2a] & 0x02))
ret <<= 1;
#endif
ac97_codec_log("AC97 Codec %d: getrate(%02X) = %d\n", dev->codec_id, reg, ret);
return ret;
}
static void *
ac97_codec_init(const device_t *info)
{
ac97_codec_t *dev = malloc(sizeof(ac97_codec_t));
memset(dev, 0, sizeof(ac97_codec_t));
dev->vendor_id = info->local;
ac97_codec_log("AC97 Codec %d: init(%c%c%c%02X)\n", ac97_codec_id, (dev->vendor_id >> 24) & 0xff, (dev->vendor_id >> 16) & 0xff, (dev->vendor_id >> 8) & 0xff, dev->vendor_id & 0xff);
/* Associate this codec to the current controller. */
if (!ac97_codec || (ac97_codec_count <= 0)) {
fatal("AC97 Codec %d: No controller to associate codec\n", ac97_codec_id);
return NULL;
}
*ac97_codec = dev;
if (--ac97_codec_count == 0)
ac97_codec = NULL;
else
ac97_codec += sizeof(ac97_codec_t *);
dev->codec_id = ac97_codec_id++;
/* Initialize codec registers. */
ac97_codec_reset(dev);
return dev;
}
static void
ac97_codec_close(void *priv)
{
ac97_codec_t *dev = (ac97_codec_t *) priv;
ac97_codec_log("AC97 Codec %d: close()\n", dev->codec_id);
free(dev);
}
const device_t ad1881_device =
{
"Analog Devices AD1881",
DEVICE_AC97,
AC97_CODEC_AD1881,
ac97_codec_init, ac97_codec_close, ac97_codec_reset,
{ NULL },
NULL,
NULL,
NULL
};
const device_t alc100_device =
{
"Avance Logic ALC100",
DEVICE_AC97,
AC97_CODEC_ALC100,
ac97_codec_init, ac97_codec_close, ac97_codec_reset,
{ NULL },
NULL,
NULL,
NULL
};
const device_t cs4297_device =
{
"Crystal CS4297",
DEVICE_AC97,
AC97_CODEC_CS4297,
ac97_codec_init, ac97_codec_close, ac97_codec_reset,
{ NULL },
NULL,
NULL,
NULL
};
const device_t cs4297a_device =
{
"Crystal CS4297A",
DEVICE_AC97,
AC97_CODEC_CS4297A,
ac97_codec_init, ac97_codec_close, ac97_codec_reset,
{ NULL },
NULL,
NULL,
NULL
};
const device_t wm9701a_device =
{
"Wolfson WM9701A",
DEVICE_AC97,
AC97_CODEC_WM9701A,
ac97_codec_init, ac97_codec_close, ac97_codec_reset,
{ NULL },
NULL,
NULL,
NULL
};

843
src/sound/snd_ac97_via.c Normal file
View File

@@ -0,0 +1,843 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* VIA AC'97 audio controller emulation.
*
*
*
* Authors: RichardG, <richardg867@gmail.com>
*
* Copyright 2021 RichardG.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/mem.h>
#include <86box/pic.h>
#include <86box/timer.h>
#include <86box/pci.h>
#include <86box/sound.h>
#include <86box/snd_ac97.h>
typedef struct {
uint8_t id, always_run;
struct _ac97_via_ *dev;
uint32_t entry_ptr, sample_ptr, fifo_pos, fifo_end;
int32_t sample_count;
uint8_t entry_flags, fifo[32], restart;
pc_timer_t timer;
} ac97_via_sgd_t;
typedef struct _ac97_via_ {
uint16_t audio_sgd_base, audio_codec_base, modem_sgd_base, modem_codec_base;
uint8_t sgd_regs[256], pcm_enabled: 1, fm_enabled: 1, vsr_enabled: 1;
struct {
union {
uint8_t regs_codec[2][128];
uint8_t regs_linear[256];
};
} codec_shadow[2];
int slot, irq_pin;
ac97_codec_t *codec[2][2];
ac97_via_sgd_t sgd[6];
pc_timer_t timer_count, timer_count_fm;
uint64_t timer_latch, timer_latch_fm;
int16_t out_l, out_r, fm_out_l, fm_out_r;
int master_vol_l, master_vol_r, pcm_vol_l, pcm_vol_r, cd_vol_l, cd_vol_r;
int32_t buffer[SOUNDBUFLEN * 2], fm_buffer[SOUNDBUFLEN * 2];
int pos, fm_pos;
} ac97_via_t;
#ifdef ENABLE_AC97_VIA_LOG
int ac97_via_do_log = ENABLE_AC97_VIA_LOG;
static void
ac97_via_log(const char *fmt, ...)
{
va_list ap;
if (ac97_via_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define ac97_via_log(fmt, ...)
#endif
static void ac97_via_sgd_process(void *priv);
static void ac97_via_update_codec(ac97_via_t *dev);
static void ac97_via_speed_changed(void *priv);
void
ac97_via_set_slot(void *priv, int slot, int irq_pin)
{
ac97_via_t *dev = (ac97_via_t *) priv;
ac97_via_log("AC97 VIA: set_slot(%d, %d)\n", slot, irq_pin);
dev->slot = slot;
dev->irq_pin = irq_pin;
}
uint8_t
ac97_via_read_status(void *priv, uint8_t modem)
{
ac97_via_t *dev = (ac97_via_t *) priv;
uint8_t ret = 0x00;
/* Flag each codec as ready if present. */
for (uint8_t i = 0; i <= 1; i++) {
if (dev->codec[modem][i])
ret |= 0x01 << (i << 1);
}
ac97_via_log("AC97 VIA %d: read_status() = %02X\n", modem, ret);
return ret;
}
void
ac97_via_write_control(void *priv, uint8_t modem, uint8_t val)
{
ac97_via_t *dev = (ac97_via_t *) priv;
uint8_t i;
ac97_via_log("AC97 VIA %d: write_control(%02X)\n", modem, val);
/* Reset codecs if requested. */
if (!(val & 0x40)) {
for (i = 0; i <= 1; i++) {
if (dev->codec[modem][i])
ac97_codec_reset(dev->codec[modem][i]);
}
}
if (!modem) {
/* Set the variable sample rate flag. */
dev->vsr_enabled = (val & 0xf8) == 0xc8;
/* Start or stop PCM playback. */
i = (val & 0xf4) == 0xc4;
if (i && !dev->pcm_enabled)
timer_advance_u64(&dev->timer_count, dev->timer_latch);
dev->pcm_enabled = i;
/* Start or stop FM playback. */
i = (val & 0xf2) == 0xc2;
if (i && !dev->fm_enabled)
timer_advance_u64(&dev->timer_count_fm, dev->timer_latch);
dev->fm_enabled = i;
/* Update primary audio codec state. */
if (dev->codec[0][0])
ac97_via_update_codec(dev);
}
}
static void
ac97_via_update_irqs(ac97_via_t *dev)
{
/* Check interrupt flags in all SGDs. */
for (uint8_t i = 0x00; i < ((sizeof(dev->sgd) / sizeof(dev->sgd[0])) << 4); i += 0x10) {
/* Stop immediately if any flag is set. Doing it this way optimizes
rising edges for the playback SGD (0 - first to be checked). */
if (dev->sgd_regs[i] & (dev->sgd_regs[i | 0x2] & 0x03)) {
pci_set_irq(dev->slot, dev->irq_pin);
return;
}
}
pci_clear_irq(dev->slot, dev->irq_pin);
}
static void
ac97_via_update_codec(ac97_via_t *dev) {
/* Get primary audio codec. */
ac97_codec_t *codec = dev->codec[0][0];
/* Update volumes according to codec registers. */
ac97_codec_getattn(codec, 0x02, &dev->master_vol_l, &dev->master_vol_r);
ac97_codec_getattn(codec, 0x18, &dev->pcm_vol_l, &dev->pcm_vol_r);
ac97_codec_getattn(codec, 0x12, &dev->cd_vol_l, &dev->cd_vol_r);
/* Update sample rate according to codec registers and the variable sample rate flag. */
ac97_via_speed_changed(dev);
}
uint8_t
ac97_via_sgd_read(uint16_t addr, void *priv)
{
ac97_via_t *dev = (ac97_via_t *) priv;
#ifdef ENABLE_AC97_VIA_LOG
uint8_t modem = (addr & 0xff00) == dev->modem_sgd_base;
#endif
addr &= 0xff;
uint8_t ret;
if (!(addr & 0x80)) {
/* Process SGD channel registers. */
switch (addr & 0xf) {
case 0x4:
ret = dev->sgd[addr >> 4].entry_ptr;
break;
case 0x5:
ret = dev->sgd[addr >> 4].entry_ptr >> 8;
break;
case 0x6:
ret = dev->sgd[addr >> 4].entry_ptr >> 16;
break;
case 0x7:
ret = dev->sgd[addr >> 4].entry_ptr >> 24;
break;
case 0xc:
ret = dev->sgd[addr >> 4].sample_count;
break;
case 0xd:
ret = dev->sgd[addr >> 4].sample_count >> 8;
break;
case 0xe:
ret = dev->sgd[addr >> 4].sample_count >> 16;
break;
default:
ret = dev->sgd_regs[addr];
break;
}
} else {
/* Process regular registers. */
switch (addr) {
case 0x84:
ret = (dev->sgd_regs[0x00] & 0x01);
ret |= (dev->sgd_regs[0x10] & 0x01) << 1;
ret |= (dev->sgd_regs[0x20] & 0x01) << 2;
ret |= (dev->sgd_regs[0x00] & 0x02) << 3;
ret |= (dev->sgd_regs[0x10] & 0x02) << 4;
ret |= (dev->sgd_regs[0x20] & 0x02) << 5;
break;
case 0x85:
ret = (dev->sgd_regs[0x00] & 0x04) >> 2;
ret |= (dev->sgd_regs[0x10] & 0x04) >> 1;
ret |= (dev->sgd_regs[0x20] & 0x04);
ret |= (dev->sgd_regs[0x00] & 0x80) >> 3;
ret |= (dev->sgd_regs[0x10] & 0x80) >> 2;
ret |= (dev->sgd_regs[0x20] & 0x80) >> 1;
break;
case 0x86:
ret = (dev->sgd_regs[0x40] & 0x01);
ret |= (dev->sgd_regs[0x50] & 0x01) << 1;
ret |= (dev->sgd_regs[0x40] & 0x02) << 3;
ret |= (dev->sgd_regs[0x50] & 0x02) << 4;
break;
case 0x87:
ret = (dev->sgd_regs[0x40] & 0x04) >> 2;
ret |= (dev->sgd_regs[0x50] & 0x04) >> 1;
ret |= (dev->sgd_regs[0x40] & 0x80) >> 3;
ret |= (dev->sgd_regs[0x50] & 0x80) >> 2;
break;
default:
ret = dev->sgd_regs[addr];
break;
}
}
ac97_via_log("AC97 VIA %d: sgd_read(%02X) = %02X\n", modem, addr, ret);
return ret;
}
void
ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv)
{
ac97_via_t *dev = (ac97_via_t *) priv;
uint8_t modem = (addr & 0xff00) == dev->modem_sgd_base, i;
ac97_codec_t *codec;
addr &= 0xff;
ac97_via_log("AC97 VIA %d: sgd_write(%02X, %02X)\n", modem, addr, val);
/* Check function-specific read only registers. */
if ((addr >= (modem ? 0x00 : 0x40)) && (addr < (modem ? 0x40 : 0x60)))
return;
if (addr >= (modem ? 0x90 : 0x88))
return;
if (!(addr & 0x80)) {
/* Process SGD channel registers. */
switch (addr & 0xf) {
case 0x0:
/* Clear RWC status bits. */
dev->sgd_regs[addr] &= ~(val & 0x07);
/* Update status interrupts. */
ac97_via_update_irqs(dev);
return;
case 0x1:
/* Start SGD if requested. */
if (val & 0x80) {
if (dev->sgd_regs[addr & 0xf0] & 0x80) {
/* Queue SGD trigger if already running. */
dev->sgd_regs[addr & 0xf0] |= 0x08;
} else {
/* Start SGD immediately. */
dev->sgd_regs[addr & 0xf0] |= 0x80;
dev->sgd_regs[addr & 0xf0] &= ~0x44;
/* Start at the specified entry pointer. */
dev->sgd[addr >> 4].sample_ptr = 0;
dev->sgd[addr >> 4].entry_ptr = *((uint32_t *) &dev->sgd_regs[(addr & 0xf0) | 0x4]) & 0xfffffffe;
dev->sgd[addr >> 4].restart = 1;
/* Start the actual SGD process. */
ac97_via_sgd_process(&dev->sgd[addr >> 4]);
}
}
/* Stop SGD if requested. */
if (val & 0x40)
dev->sgd_regs[addr & 0xf0] &= ~0x88;
val &= 0x08;
/* (Un)pause SGD if requested. */
if (val & 0x08)
dev->sgd_regs[addr & 0xf0] |= 0x40;
else
dev->sgd_regs[addr & 0xf0] &= ~0x40;
break;
case 0x2:
if (addr & 0x10)
val &= 0xf3;
break;
case 0x3: case 0x8 ... 0xf:
/* Read-only registers. */
return;
}
} else {
/* Process regular registers. */
switch (addr) {
case 0x30 ... 0x3f:
case 0x60 ... 0x7f:
case 0x84 ... 0x87:
/* Read-only registers. */
return;
case 0x82:
/* Determine the selected codec. */
i = !!(dev->sgd_regs[0x83] & 0x40);
codec = dev->codec[modem][i];
/* Keep value in register if this codec is not present. */
if (codec) {
/* Read from or write to codec. */
if (val & 0x80) {
if (val & 1) { /* return 0x00 on unaligned reads */
dev->sgd_regs[0x80] = dev->sgd_regs[0x81] = 0x00;
} else {
dev->sgd_regs[0x80] = dev->codec_shadow[modem].regs_codec[i][val] = ac97_codec_read(codec, val);
dev->sgd_regs[0x81] = dev->codec_shadow[modem].regs_codec[i][val | 1] = ac97_codec_read(codec, val | 1);
}
/* Flag data/status/index for this codec as valid. */
if (val & 0x80)
dev->sgd_regs[0x83] |= 0x02 << (i << 1);
} else if (!(val & 1)) { /* do nothing on unaligned writes */
ac97_codec_write(codec, val, dev->codec_shadow[modem].regs_codec[i][val] = dev->sgd_regs[0x80]);
ac97_codec_write(codec, val | 1, dev->codec_shadow[modem].regs_codec[i][val | 1] = dev->sgd_regs[0x81]);
/* Update primary audio codec state if that codec was written to. */
if (!modem && !i)
ac97_via_update_codec(dev);
}
}
break;
case 0x83:
/* Clear RWC status bits. */
#if 0 /* race condition with Linux accessing a register and clearing status bits on the same dword write */
val = (dev->sgd_regs[addr] & ~(val & 0x0a)) | (val & 0xc0);
#else
val = dev->sgd_regs[addr] | (val & 0xc0);
#endif
break;
}
}
dev->sgd_regs[addr] = val;
}
void
ac97_via_remap_audio_sgd(void *priv, uint16_t new_io_base, uint8_t enable)
{
ac97_via_t *dev = (ac97_via_t *) priv;
if (dev->audio_sgd_base)
io_removehandler(dev->audio_sgd_base, 256, ac97_via_sgd_read, NULL, NULL, ac97_via_sgd_write, NULL, NULL, dev);
dev->audio_sgd_base = new_io_base;
if (dev->audio_sgd_base && enable)
io_sethandler(dev->audio_sgd_base, 256, ac97_via_sgd_read, NULL, NULL, ac97_via_sgd_write, NULL, NULL, dev);
}
void
ac97_via_remap_modem_sgd(void *priv, uint16_t new_io_base, uint8_t enable)
{
ac97_via_t *dev = (ac97_via_t *) priv;
if (dev->modem_sgd_base)
io_removehandler(dev->modem_sgd_base, 256, ac97_via_sgd_read, NULL, NULL, ac97_via_sgd_write, NULL, NULL, dev);
dev->modem_sgd_base = new_io_base;
if (dev->modem_sgd_base && enable)
io_sethandler(dev->modem_sgd_base, 256, ac97_via_sgd_read, NULL, NULL, ac97_via_sgd_write, NULL, NULL, dev);
}
uint8_t
ac97_via_codec_read(uint16_t addr, void *priv)
{
ac97_via_t *dev = (ac97_via_t *) priv;
uint8_t modem = (addr & 0xff00) == dev->modem_codec_base;
addr &= 0xff;
uint8_t ret = 0xff;
ret = dev->codec_shadow[modem].regs_linear[addr];
ac97_via_log("AC97 VIA %d: codec_read(%02X) = %02X\n", modem, addr, ret);
return ret;
}
void
ac97_via_codec_write(uint16_t addr, uint8_t val, void *priv)
{
ac97_via_t *dev = (ac97_via_t *) priv;
uint8_t modem = (addr & 0xff00) == dev->modem_codec_base;
addr &= 0xff;
ac97_via_log("AC97 VIA %d: codec_write(%02X, %02X)\n", modem, addr, val);
/* Unknown behavior, maybe it does write to the shadow registers? */
dev->codec_shadow[modem].regs_linear[addr] = val;
}
void
ac97_via_remap_audio_codec(void *priv, uint16_t new_io_base, uint8_t enable)
{
ac97_via_t *dev = (ac97_via_t *) priv;
if (dev->audio_codec_base)
io_removehandler(dev->audio_codec_base, 256, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev);
dev->audio_codec_base = new_io_base;
if (dev->audio_codec_base && enable)
io_sethandler(dev->audio_codec_base, 256, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev);
}
void
ac97_via_remap_modem_codec(void *priv, uint16_t new_io_base, uint8_t enable)
{
ac97_via_t *dev = (ac97_via_t *) priv;
if (dev->modem_codec_base)
io_removehandler(dev->modem_codec_base, 256, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev);
dev->modem_codec_base = new_io_base;
if (dev->modem_codec_base && enable)
io_sethandler(dev->modem_codec_base, 256, ac97_via_codec_read, NULL, NULL, ac97_via_codec_write, NULL, NULL, dev);
}
static void
ac97_via_update(ac97_via_t *dev)
{
int32_t l = (((dev->out_l * dev->pcm_vol_l) >> 15) * dev->master_vol_l) >> 15,
r = (((dev->out_r * dev->pcm_vol_r) >> 15) * dev->master_vol_r) >> 15;
if (l < -32768)
l = -32768;
else if (l > 32767)
l = 32767;
if (r < -32768)
r = -32768;
else if (r > 32767)
r = 32767;
for (; dev->pos < sound_pos_global; dev->pos++) {
dev->buffer[dev->pos*2] = l;
dev->buffer[dev->pos*2 + 1] = r;
}
}
static void
ac97_via_update_fm(ac97_via_t *dev)
{
for (; dev->fm_pos < sound_pos_global; dev->fm_pos++) {
dev->fm_buffer[dev->fm_pos*2] = dev->fm_out_l;
dev->fm_buffer[dev->fm_pos*2 + 1] = dev->fm_out_r;
}
}
static void
ac97_via_sgd_process(void *priv)
{
ac97_via_sgd_t *sgd = (ac97_via_sgd_t *) priv;
ac97_via_t *dev = sgd->dev;
/* Stop if this SGD is not active. */
uint8_t sgd_status = dev->sgd_regs[sgd->id] & 0xc4;
if (!(sgd_status & 0x80))
return;
/* Schedule next run. */
timer_on_auto(&sgd->timer, 10.0);
/* Process SGD if it's active, and the FIFO has room or is disabled. */
if ((sgd_status == 0x80) && (sgd->always_run || ((sgd->fifo_end - sgd->fifo_pos) <= (sizeof(sgd->fifo) - 4)))) {
/* Move on to the next block if no entry is present. */
if (sgd->restart) {
sgd->restart = 0;
/* Start at first entry if no pointer is present. */
if (!sgd->entry_ptr)
sgd->entry_ptr = *((uint32_t *) &dev->sgd_regs[sgd->id | 0x4]) & 0xfffffffe;
/* Read entry. */
sgd->sample_ptr = mem_readl_phys(sgd->entry_ptr);
sgd->entry_ptr += 4;
sgd->sample_count = mem_readl_phys(sgd->entry_ptr);
sgd->entry_ptr += 4;
#ifdef ENABLE_AC97_VIA_LOG
if (((sgd->sample_ptr == 0xffffffff) && (sgd->sample_count == 0xffffffff)) ||
((sgd->sample_ptr == 0x00000000) && (sgd->sample_count == 0x00000000)))
fatal("AC97 VIA: Invalid SGD %d entry %08X%08X at %08X\n", sgd->id >> 4,
sgd->sample_ptr, sgd->sample_count, sgd->entry_ptr - 8);
#endif
/* Extract flags from the most significant byte. */
sgd->entry_flags = sgd->sample_count >> 24;
sgd->sample_count &= 0xffffff;
ac97_via_log("AC97 VIA: Starting SGD %d block at %08X start %08X len %06X flags %02X\n", sgd->id >> 4,
sgd->entry_ptr - 8, sgd->sample_ptr, sgd->sample_count, sgd->entry_flags);
}
if (sgd->id & 0x10) {
/* Write channel: read data from FIFO. */
mem_writel_phys(sgd->sample_ptr, *((uint32_t *) &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)]));
} else {
/* Read channel: write data to FIFO. */
*((uint32_t *) &sgd->fifo[sgd->fifo_end & (sizeof(sgd->fifo) - 1)]) = mem_readl_phys(sgd->sample_ptr);
}
sgd->fifo_end += 4;
sgd->sample_ptr += 4;
sgd->sample_count -= 4;
/* Check if we've hit the end of this block. */
if (sgd->sample_count <= 0) {
ac97_via_log("AC97 VIA: Ending SGD %d block", sgd->id >> 4);
if (sgd->entry_flags & 0x20) {
ac97_via_log(" with STOP");
/* Raise STOP to pause SGD. */
dev->sgd_regs[sgd->id] |= 0x04;
}
if (sgd->entry_flags & 0x40) {
ac97_via_log(" with FLAG");
/* Raise FLAG and STOP. */
dev->sgd_regs[sgd->id] |= 0x05;
#ifdef ENABLE_AC97_VIA_LOG
if (dev->sgd_regs[sgd->id | 0x2] & 0x01)
ac97_via_log(" interrupt");
#endif
}
if (sgd->entry_flags & 0x80) {
ac97_via_log(" with EOL");
/* Raise EOL. */
dev->sgd_regs[sgd->id] |= 0x02;
#ifdef ENABLE_AC97_VIA_LOG
if (dev->sgd_regs[sgd->id | 0x2] & 0x02)
ac97_via_log(" interrupt");
#endif
/* Restart SGD if a trigger is queued or auto-start is enabled. */
if ((dev->sgd_regs[sgd->id] & 0x08) || (dev->sgd_regs[sgd->id | 0x2] & 0x80)) {
ac97_via_log(" restart");
/* Un-queue trigger. */
dev->sgd_regs[sgd->id] &= ~0x08;
/* Go back to the starting block. */
sgd->entry_ptr = 0; /* ugly, but Windows XP plays too fast if the pointer is reloaded now */
} else {
ac97_via_log(" finish");
/* Terminate SGD. */
dev->sgd_regs[sgd->id] &= ~0x80;
}
}
ac97_via_log("\n");
/* Fire any requested status interrupts. */
ac97_via_update_irqs(dev);
/* Move on to a new block on the next run. */
sgd->restart = 1;
}
}
}
static void
ac97_via_poll(void *priv)
{
ac97_via_t *dev = (ac97_via_t *) priv;
ac97_via_sgd_t *sgd = &dev->sgd[0]; /* Audio Read */
/* Schedule next run if PCM playback is enabled. */
if (dev->pcm_enabled)
timer_advance_u64(&dev->timer_count, dev->timer_latch);
/* Update audio buffer. */
ac97_via_update(dev);
/* Feed next sample from the FIFO. */
switch (dev->sgd_regs[0x02] & 0x30) {
case 0x00: /* Mono, 8-bit PCM */
if ((sgd->fifo_end - sgd->fifo_pos) >= 1) {
dev->out_l = dev->out_r = (sgd->fifo[sgd->fifo_pos++ & (sizeof(sgd->fifo) - 1)] ^ 0x80) << 8;
return;
}
break;
case 0x10: /* Stereo, 8-bit PCM */
if ((sgd->fifo_end - sgd->fifo_pos) >= 2) {
dev->out_l = (sgd->fifo[sgd->fifo_pos++ & (sizeof(sgd->fifo) - 1)] ^ 0x80) << 8;
dev->out_r = (sgd->fifo[sgd->fifo_pos++ & (sizeof(sgd->fifo) - 1)] ^ 0x80) << 8;
return;
}
break;
case 0x20: /* Mono, 16-bit PCM */
if ((sgd->fifo_end - sgd->fifo_pos) >= 2) {
dev->out_l = dev->out_r = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]);
sgd->fifo_pos += 2;
return;
}
break;
case 0x30: /* Stereo, 16-bit PCM */
if ((sgd->fifo_end - sgd->fifo_pos) >= 4) {
dev->out_l = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]);
sgd->fifo_pos += 2;
dev->out_r = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]);
sgd->fifo_pos += 2;
return;
}
break;
}
/* Feed silence if the FIFO is empty. */
dev->out_l = dev->out_r = 0;
}
static void
ac97_via_poll_fm(void *priv)
{
ac97_via_t *dev = (ac97_via_t *) priv;
ac97_via_sgd_t *sgd = &dev->sgd[2]; /* FM Read */
/* Schedule next run if FM playback is enabled. */
if (dev->fm_enabled)
timer_advance_u64(&dev->timer_count_fm, dev->timer_latch_fm);
/* Update FM audio buffer. */
ac97_via_update_fm(dev);
/* Feed next sample from the FIFO.
The data format is not documented, but it probes as 16-bit stereo at 24 KHz. */
if ((sgd->fifo_end - sgd->fifo_pos) >= 4) {
dev->out_l = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]);
sgd->fifo_pos += 2;
dev->out_r = *((uint16_t *) &sgd->fifo[sgd->fifo_pos & (sizeof(sgd->fifo) - 1)]);
sgd->fifo_pos += 2;
return;
}
/* Feed silence if the FIFO is empty. */
dev->fm_out_l = dev->fm_out_r = 0;
}
static void
ac97_via_get_buffer(int32_t *buffer, int len, void *priv)
{
ac97_via_t *dev = (ac97_via_t *) priv;
ac97_via_update(dev);
ac97_via_update_fm(dev);
for (int c = 0; c < len * 2; c++) {
buffer[c] += dev->buffer[c] / 2;
buffer[c] += dev->fm_buffer[c] / 2;
}
dev->pos = dev->fm_pos = 0;
}
static void
via_ac97_filter_cd_audio(int channel, double *buffer, void *priv)
{
ac97_via_t *dev = (ac97_via_t *) priv;
double c, volume = channel ? dev->cd_vol_r : dev->cd_vol_l;
c = ((*buffer) * volume) / 65536.0;
*buffer = c;
}
static void
ac97_via_speed_changed(void *priv)
{
ac97_via_t *dev = (ac97_via_t *) priv;
double freq;
/* Get variable sample rate if enabled. */
if (dev->vsr_enabled && dev->codec[0][0])
freq = ac97_codec_getrate(dev->codec[0][0], 0x2c);
else
freq = 48000.0;
dev->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / freq));
dev->timer_latch_fm = (uint64_t) ((double) TIMER_USEC * (1000000.0 / 24000.0));
}
static void *
ac97_via_init(const device_t *info)
{
ac97_via_t *dev = malloc(sizeof(ac97_via_t));
memset(dev, 0, sizeof(ac97_via_t));
ac97_via_log("AC97 VIA: init()\n");
/* Set up codecs. */
ac97_codec = &dev->codec[0][0];
ac97_modem_codec = &dev->codec[1][0];
ac97_codec_count = ac97_modem_codec_count = sizeof(dev->codec[0]) / sizeof(dev->codec[0][0]);
ac97_codec_id = ac97_modem_codec_id = 0;
/* Set up SGD channels. */
for (uint8_t i = 0; i < (sizeof(dev->sgd) / sizeof(dev->sgd[0])); i++) {
dev->sgd[i].id = i << 4;
dev->sgd[i].dev = dev;
/* Disable the FIFO on SGDs we don't care about. */
if ((i != 0) && (i != 2))
dev->sgd[i].always_run = 1;
timer_add(&dev->sgd[i].timer, ac97_via_sgd_process, &dev->sgd[i], 0);
}
/* Set up playback pollers. */
timer_add(&dev->timer_count, ac97_via_poll, dev, 0);
timer_add(&dev->timer_count_fm, ac97_via_poll_fm, dev, 0);
ac97_via_speed_changed(dev);
/* Set up playback handler. */
sound_add_handler(ac97_via_get_buffer, dev);
/* Set up CD audio filter. */
sound_set_cd_audio_filter(via_ac97_filter_cd_audio, dev);
return dev;
}
static void
ac97_via_close(void *priv)
{
ac97_via_t *dev = (ac97_via_t *) priv;
ac97_via_log("AC97 VIA: close()\n");
free(dev);
}
const device_t ac97_via_device =
{
"VIA VT82C686 Integrated AC97 Controller",
DEVICE_PCI,
0,
ac97_via_init, ac97_via_close, NULL,
{ NULL },
ac97_via_speed_changed,
NULL,
NULL
};

View File

@@ -17,6 +17,7 @@
#include <86box/sound.h>
#include <86box/midi.h>
#include <86box/snd_mpu401.h>
#include <86box/snd_ac97.h>
#define N 16
@@ -51,7 +52,7 @@ typedef struct {
uint8_t uart_ctrl;
uint8_t uart_status;
uint16_t codec_regs[128];
ac97_codec_t *codec;
uint32_t codec_ctrl;
struct {
@@ -147,12 +148,6 @@ typedef struct {
#define FORMAT_MONO_16 2
#define FORMAT_STEREO_16 3
const int32_t codec_attn[]= {
25,32,41,51,65,82,103,130,164,206,260,327,412,519,653,
822,1036,1304,1641,2067,2602,3276,4125,5192,6537,8230,10362,13044,
16422,20674,26027,32767
};
static void es1371_fetch(es1371_t *es1371, int dac_nr);
static void update_legacy(es1371_t *es1371, uint32_t old_legacy_ctrl);
@@ -332,7 +327,8 @@ static uint16_t es1371_inw(uint16_t port, void *p)
break;
default:
audiopci_log("Bad es1371_inw: port=%04x\n", port);
ret = es1371_inb(port, p);
ret |= es1371_inb(port + 1, p) << 8;
}
// audiopci_log("es1371_inw: port=%04x ret=%04x %04x:%08x\n", port, ret, CS,cpu_state.pc);
@@ -358,11 +354,7 @@ static uint32_t es1371_inl(uint16_t port, void *p)
break;
case 0x14:
ret = es1371->codec_ctrl & 0x00ff0000;
ret |= es1371->codec_regs[(es1371->codec_ctrl >> 16) & 0x7f];
if (((es1371->codec_ctrl >> 16) & 0x7f) == 0x26)
ret |= 0x0f;
ret |= CODEC_READY;
ret = es1371->codec_ctrl | CODEC_READY;
break;
case 0x30:
@@ -416,7 +408,8 @@ static uint32_t es1371_inl(uint16_t port, void *p)
break;
default:
audiopci_log("Bad es1371_inl: port=%04x\n", port);
ret = es1371_inw(port, p);
ret |= es1371_inw(port + 2, p) << 16;
}
audiopci_log("es1371_inl: port=%04x ret=%08x\n", port, ret);
@@ -527,7 +520,8 @@ static void es1371_outw(uint16_t port, uint16_t val, void *p)
break;
default:
audiopci_log("Bad es1371_outw: port=%04x val=%04x\n", port, val);
es1371_outb(port, val & 0xff, p);
es1371_outb(port + 1, (val >> 8) & 0xff, p);
}
}
static void es1371_outl(uint16_t port, uint32_t val, void *p)
@@ -593,39 +587,18 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p)
break;
case 0x14:
es1371->codec_ctrl = val;
if (!(val & CODEC_READ))
{
// audiopci_log("Write codec %02x %04x\n", (val >> 16) & 0x7f, val & 0xffff);
if ((((val >> 16) & 0x7f) != 0x7c) && (((val >> 16) & 0x7f) != 0x7e))
es1371->codec_regs[(val >> 16) & 0x7f] = val & 0xffff;
switch ((val >> 16) & 0x7f)
{
case 0x02: /*Master volume*/
if (val & 0x8000)
es1371->master_vol_l = es1371->master_vol_r = 0;
else
{
if (val & 0x2000)
es1371->master_vol_l = codec_attn[0];
else
es1371->master_vol_l = codec_attn[0x1f - ((val >> 8) & 0x1f)];
if (val & 0x20)
es1371->master_vol_r = codec_attn[0];
else
es1371->master_vol_r = codec_attn[0x1f - (val & 0x1f)];
}
break;
case 0x12: /*CD volume*/
if (val & 0x8000)
es1371->cd_vol_l = es1371->cd_vol_r = 0;
else
{
es1371->cd_vol_l = codec_attn[0x1f - ((val >> 8) & 0x1f)];
es1371->cd_vol_r = codec_attn[0x1f - (val & 0x1f)];
}
break;
}
if (val & CODEC_READ) {
es1371->codec_ctrl &= 0x00ff0000;
val = (val >> 16) & 0x7e;
es1371->codec_ctrl |= ac97_codec_read(es1371->codec, val);
es1371->codec_ctrl |= ac97_codec_read(es1371->codec, val | 1) << 8;
} else {
es1371->codec_ctrl = val & 0x00ffffff;
ac97_codec_write(es1371->codec, (val >> 16) & 0x7e, val & 0xff);
ac97_codec_write(es1371->codec, ((val >> 16) & 0x7e) | 1, val >> 8);
ac97_codec_getattn(es1371->codec, 0x02, &es1371->master_vol_l, &es1371->master_vol_r);
ac97_codec_getattn(es1371->codec, 0x12, &es1371->cd_vol_l, &es1371->cd_vol_r);
}
break;
@@ -730,7 +703,8 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p)
break;
default:
audiopci_log("Bad es1371_outl: port=%04x val=%08x\n", port, val);
es1371_outw(port, val & 0xffff, p);
es1371_outw(port + 2, (val >> 16) & 0xffff, p);
}
}
@@ -1362,9 +1336,11 @@ static void *es1371_init(const device_t *info)
generate_es1371_filter();
/* Return a CS4297A like VMware does. */
es1371->codec_regs[0x7c] = 0x4352;
es1371->codec_regs[0x7e] = 0x5910;
ac97_codec = &es1371->codec;
ac97_codec_count = 1;
ac97_codec_id = 0;
if (!info->local) /* let the machine decide the codec on onboard implementations */
device_add(&cs4297a_device);
return es1371;
}

View File

@@ -19,7 +19,7 @@
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <math.h>
#include <math.h>
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/timer.h>
@@ -34,6 +34,7 @@
#include <86box/snd_ad1848.h>
#include <86box/snd_opl.h>
#include <86box/snd_sb.h>
#include <86box/nvr.h>
enum {
@@ -132,9 +133,10 @@ typedef struct cs423x_t
void *gameport;
void *i2c, *eeprom;
uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size: 11;
uint8_t type, ad1848_type, pnp_offset, regs[8], indirect_regs[16],
eeprom_data[2048], ram_data[384], ram_dl: 2, opl_wss: 1;
uint16_t wss_base, opl_base, sb_base, ctrl_base, ram_addr, eeprom_size: 11, pnp_offset;
uint8_t type, ad1848_type, regs[8], indirect_regs[16],
eeprom_data[2048], ram_data[65536], ram_dl: 2, opl_wss: 1;
char *nvr_path;
uint8_t pnp_enable: 1, key_pos: 5, slam_enable: 1, slam_state: 2, slam_ld, slam_reg;
isapnp_device_config_t *slam_config;
@@ -146,6 +148,20 @@ static void cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_
static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv);
static void
cs423x_nvram(cs423x_t *dev, uint8_t save)
{
FILE *f = nvr_fopen(dev->nvr_path, save ? "wb" : "rb");
if (f) {
if (save)
fwrite(dev->eeprom_data, sizeof(dev->eeprom_data), 1, f);
else
fread(dev->eeprom_data, sizeof(dev->eeprom_data), 1, f);
fclose(f);
}
}
static uint8_t
cs423x_read(uint16_t addr, void *priv)
{
@@ -165,14 +181,9 @@ cs423x_read(uint16_t addr, void *priv)
break;
case 5: /* Control/RAM Access */
/* Reading RAM is undocumented; the WDM driver does so. */
if (dev->ram_dl == 3) {
if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) /* chip configuration and PnP resources */
ret = dev->ram_data[dev->ram_addr & 0x01ff];
else
ret = 0xff;
dev->ram_addr++;
}
/* Reading RAM is undocumented; the Windows drivers do so. */
if (dev->ram_dl == 3)
ret = dev->ram_data[dev->ram_addr++];
break;
case 7: /* Global Status */
@@ -295,9 +306,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv)
break;
case 3: /* data */
if ((dev->ram_addr >= 0x4000) && (dev->ram_addr < 0x4180)) /* chip configuration and PnP resources */
dev->ram_data[dev->ram_addr & 0x01ff] = val;
dev->ram_addr++;
dev->ram_data[dev->ram_addr++] = val;
break;
}
break;
@@ -452,7 +461,7 @@ cs423x_slam_enable(cs423x_t *dev, uint8_t enable)
}
/* Enable SLAM if the CKD bit is not set. */
if (enable && !(dev->ram_data[2] & 0x10)) {
if (enable && !(dev->ram_data[0x4002] & 0x10)) {
dev->slam_enable = 1;
io_sethandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev);
}
@@ -527,25 +536,22 @@ cs423x_get_buffer(int32_t *buffer, int len, void *priv)
static void
cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig)
{
uint8_t enable = ISAPNP_CARD_ENABLE;
if (dev->pnp_card) {
/* Hide PnP card if the PKD bit is set, or if PnP was disabled by command 0x55. */
if ((dev->ram_data[2] & 0x20) || !dev->pnp_enable)
enable = ISAPNP_CARD_DISABLE;
/* Update PnP resource data if requested. */
if (update_rom)
isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], sizeof(dev->ram_data) - dev->pnp_offset);
isapnp_update_card_rom(dev->pnp_card, &dev->ram_data[dev->pnp_offset], 384);
/* Update PnP state. */
isapnp_enable_card(dev->pnp_card, enable);
/* Hide PnP card if the PKD bit is set, or if PnP was disabled by command 0x55. */
if ((dev->ram_data[0x4002] & 0x20) || !dev->pnp_enable)
isapnp_enable_card(dev->pnp_card, ISAPNP_CARD_DISABLE);
else
isapnp_enable_card(dev->pnp_card, ISAPNP_CARD_ENABLE);
}
/* Update some register bits based on the config data in RAM if requested. */
if (update_hwconfig) {
/* Update WTEN. */
if (dev->ram_data[3] & 0x08) {
if (dev->ram_data[0x4003] & 0x08) {
dev->indirect_regs[8] |= 0x08;
dev->ad1848.wten = 1;
} else {
@@ -554,13 +560,13 @@ cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig)
}
/* Update SPS. */
if (dev->ram_data[3] & 0x04)
if (dev->ram_data[0x4003] & 0x04)
dev->indirect_regs[8] |= 0x04;
else
dev->indirect_regs[8] &= ~0x04;
/* Update IFM. */
if (dev->ram_data[3] & 0x80)
if (dev->ram_data[0x4003] & 0x80)
dev->ad1848.xregs[4] |= 0x10;
else
dev->ad1848.xregs[4] &= ~0x10;
@@ -677,13 +683,20 @@ cs423x_reset(void *priv)
{
cs423x_t *dev = (cs423x_t *) priv;
/* Load EEPROM data to RAM, or just clear RAM if there's no EEPROM. */
if (dev->eeprom)
memcpy(dev->ram_data, &dev->eeprom_data[4], MIN(sizeof(dev->ram_data), sizeof(dev->eeprom_data) - 4));
else
memset(dev->ram_data, 0, sizeof(dev->ram_data));
/* Clear RAM. */
memset(dev->ram_data, 0, sizeof(dev->ram_data));
if (dev->eeprom) {
/* Load EEPROM data to RAM. */
memcpy(&dev->ram_data[0x4000], &dev->eeprom_data[4], MIN(384, ((dev->eeprom_data[2] << 8) | dev->eeprom_data[3]) - 4));
/* Save EEPROM contents to file. */
cs423x_nvram(dev, 1);
}
/* Reset registers. */
memset(dev->regs, 0, sizeof(dev->regs));
dev->regs[1] = 0x80;
memset(dev->indirect_regs, 0, sizeof(dev->indirect_regs));
dev->indirect_regs[1] = dev->type;
if (dev->type == CRYSTAL_CS4238B)
@@ -717,7 +730,7 @@ cs423x_init(const device_t *info)
case CRYSTAL_CS4238B:
/* Same WSS codec and EEPROM structure. */
dev->ad1848_type = AD1848_TYPE_CS4236;
dev->pnp_offset = 19;
dev->pnp_offset = 0x4013;
/* Different Chip Version and ID registers, which shouldn't be reset by ad1848_init */
dev->ad1848.xregs[25] = dev->type;
@@ -729,17 +742,26 @@ cs423x_init(const device_t *info)
dev->eeprom_data[2] = sizeof(cs4236b_eeprom) >> 8;
dev->eeprom_data[3] = sizeof(cs4236b_eeprom) & 0xff;
/* Set PnP card ID. */
/* Set PnP card ID and EEPROM file name. */
switch (dev->type) {
case CRYSTAL_CS4236B:
dev->nvr_path = "cs4236b.nvr";
break;
case CRYSTAL_CS4237B:
dev->eeprom_data[26] = 0x37;
dev->nvr_path = "cs4237b.nvr";
break;
case CRYSTAL_CS4238B:
dev->eeprom_data[26] = 0x38;
dev->nvr_path = "cs4238b.nvr";
break;
}
/* Load EEPROM contents from file if present. */
cs423x_nvram(dev, 0);
/* Initialize game port. The '7B and '8B game port only responds to 6 I/O ports; the remaining
2 ports are reserved on those chips, and probably connected to the Digital Assist feature. */
dev->gameport = gameport_add((dev->type == CRYSTAL_CS4236B) ? &gameport_pnp_device : &gameport_pnp_6io_device);
@@ -759,7 +781,7 @@ cs423x_init(const device_t *info)
/* Initialize SBPro codec first to get the correct CD audio filter for the default
context, which is SBPro. The WSS codec is initialized later by cs423x_reset */
dev->sb = (sb_t *) device_add(&sb_pro_cs423x_device);
dev->sb = device_add(&sb_pro_compat_device);
/* Initialize RAM, registers and WSS codec. */
cs423x_reset(dev);
@@ -774,8 +796,11 @@ cs423x_close(void *priv)
{
cs423x_t *dev = (cs423x_t *) priv;
if (dev->eeprom)
/* Save EEPROM contents to file. */
if (dev->eeprom) {
cs423x_nvram(dev, 1);
i2c_eeprom_close(dev->eeprom);
}
i2c_gpio_close(dev->i2c);

View File

@@ -38,6 +38,8 @@
#include <86box/filters.h>
#include <86box/isapnp.h>
#include <86box/snd_sb.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
/* 0 to 7 -> -14dB to 0dB i 2dB steps. 8 to 15 -> 0 to +14dB in 2dB steps.
@@ -73,24 +75,81 @@ static const int sb_pro_mcv_irqs[4] = {7, 5, 3, 3};
/* Each card in the SB16 family has a million variants, and it shows in the large variety of device IDs for the PnP models.
These ROMs were reconstructed in a best-effort basis, around what Linux pnpdump configs and kernel logs could be found
in mailing lists, forums and other places, as well as Linux's own SB PnP card tables for ALSA and OSS. */
This ROM was reconstructed in a best-effort basis around a pnpdump output log found in a forum. */
static uint8_t sb_16_pnp_rom[] = {
0x0e, 0x8c, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0028, dummy checksum (filled in by isapnp_add_card) */
0x0e, 0x8c, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0024, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
0x82, 0x11, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', '1', '6', ' ', 'P', 'n', 'P', /* ANSI identifier */
0x15, 0x0e, 0x8c, 0x00, 0x31, 0x00, /* logical device CTL0031 */
0x16, 0x0e, 0x8c, 0x00, 0x31, 0x00, 0x65, /* logical device CTL0031, supports vendor-specific registers 0x39/0x3A/0x3D/0x3F */
0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */
0x30, /* start dependent functions, acceptable */
0x31, 0x00, /* start dependent functions, preferred */
0x22, 0x20, 0x00, /* IRQ 5 */
0x2a, 0x02, 0x08, /* DMA 1, compatibility, no count by word, count by byte, not bus master, 8-bit only */
0x2a, 0x20, 0x12, /* DMA 5, compatibility, count by word, no count by byte, not bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x20, 0x02, 0x01, 0x10, /* I/O 0x220, decodes 16-bit, 1-byte alignment, 16 addresses */
0x47, 0x01, 0x30, 0x03, 0x30, 0x03, 0x01, 0x02, /* I/O 0x330, decodes 16-bit, 1-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */
0x31, 0x01, /* start dependent functions, acceptable */
0x22, 0xa0, 0x04, /* IRQ 5/7/10 */
0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x2a, 0xe0, 0x12, /* DMA 5/6/7, compatibility, count by word, no count by byte, not bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */
0x31, 0x01, /* start dependent functions, acceptable */
0x22, 0xa0, 0x04, /* IRQ 5/7/10 */
0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */
0x2a, 0xe0, 0x12, /* DMA 5/6/7, compatibility, count by word, no count by byte, not bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x31, 0x02, /* start dependent functions, functional */
0x22, 0xa0, 0x04, /* IRQ 5/7/10 */
0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */
0x2a, 0xe0, 0x12, /* DMA 5/6/7, compatibility, count by word, no count by byte, not bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x31, 0x02, /* start dependent functions, functional */
0x22, 0xa0, 0x04, /* IRQ 5/7/10 */
0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */
0x31, 0x02, /* start dependent functions, functional */
0x22, 0xa0, 0x04, /* IRQ 5/7/10 */
0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x31, 0x02, /* start dependent functions, functional */
0x22, 0xa0, 0x04, /* IRQ 5/7/10 */
0x2a, 0x0b, 0x08, /* DMA 0/1/3, compatibility, no count by word, count by byte, not bus master, 8-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x38, /* end dependent functions */
0x16, 0x0e, 0x8c, 0x20, 0x11, 0x00, 0x5a, /* logical device CTL2011, supports vendor-specific registers 0x39/0x3B/0x3C/0x3E */
0x1c, 0x41, 0xd0, 0x06, 0x00, /* compatible device PNP0600 */
0x82, 0x03, 0x00, 'I', 'D', 'E', /* ANSI identifier */
0x31, 0x00, /* start dependent functions, preferred */
0x22, 0x00, 0x04, /* IRQ 10 */
0x47, 0x01, 0x68, 0x01, 0x68, 0x01, 0x01, 0x08, /* I/O 0x168, decodes 16-bit, 1-byte alignment, 8 addresses */
0x47, 0x01, 0x6e, 0x03, 0x6e, 0x03, 0x01, 0x02, /* I/O 0x36E, decodes 16-bit, 1-byte alignment, 2 addresses */
0x31, 0x01, /* start dependent functions, acceptable */
0x22, 0x00, 0x08, /* IRQ 11 */
0x47, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0x01, 0x08, /* I/O 0x1E8, decodes 16-bit, 1-byte alignment, 8 addresses */
0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x02, /* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 2 addresses */
0x31, 0x01, /* start dependent functions, acceptable */
0x22, 0x00, 0x8c, /* IRQ 10/11/15 */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x01, 0x08, 0x08, /* I/O 0x100-0x1F8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x47, 0x01, 0x00, 0x03, 0xfe, 0x03, 0x02, 0x02, /* I/O 0x300-0x3FE, decodes 16-bit, 2-byte alignment, 2 addresses */
0x31, 0x02, /* start dependent functions, functional */
0x22, 0x00, 0x80, /* IRQ 15 */
0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x01, 0x08, /* I/O 0x170, decodes 16-bit, 1-byte alignment, 8 addresses */
0x47, 0x01, 0x76, 0x03, 0x76, 0x03, 0x01, 0x02, /* I/O 0x376, decodes 16-bit, 1-byte alignment, 1 addresses */
0x38, /* end dependent functions */
0x16, 0x41, 0xd0, 0xff, 0xff, 0x00, 0xda, /* logical device PNPFFFF, supports vendor-specific registers 0x38/0x39/0x3B/0x3C/0x3E */
0x82, 0x08, 0x00, 'R', 'e', 's', 'e', 'r', 'v', 'e', 'd', /* ANSI identifier */
0x47, 0x01, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x01, /* I/O 0x100-0x3F8, decodes 16-bit, 8-byte alignment, 1 address */
0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */
0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */
0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */
@@ -98,227 +157,6 @@ static uint8_t sb_16_pnp_rom[] = {
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
};
static uint8_t sb_32_pnp_rom[] = {
0x0e, 0x8c, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0048, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
0x82, 0x11, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', '3', '2', ' ', 'P', 'n', 'P', /* ANSI identifier */
0x16, 0x0e, 0x8c, 0x00, 0x31, 0x00, 0xa9, /* logical device CTL0031, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */
0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */
0x31, 0x00, /* start dependent functions, preferred */
0x22, 0x20, 0x00, /* IRQ 5 */
0x2a, 0x02, 0x0c, /* DMA 1, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0x20, 0x16, /* DMA 5, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x20, 0x02, 0x01, 0x10, /* I/O 0x220, decodes 16-bit, 1-byte alignment, 16 addresses */
0x47, 0x01, 0x30, 0x03, 0x30, 0x03, 0x01, 0x02, /* I/O 0x330, decodes 16-bit, 1-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0x94, 0x03, 0x04, 0x04, /* I/O 0x388-0x394, decodes 16-bit, 4-byte alignment, 4 addresses */
0x38, /* end dependent functions */
0x16, 0x0e, 0x8c, 0x00, 0x21, 0x00, 0xa9, /* logical device CTL0021, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */
0x82, 0x09, 0x00, 'W', 'a', 'v', 'e', 'T', 'a', 'b', 'l', 'e', /* ANSI identifier */
0x31, 0x00, /* start dependent functions, preferred */
0x47, 0x01, 0x20, 0x06, 0x20, 0x06, 0x01, 0x04, /* I/O 0x620, decodes 16-bit, 1-byte alignment, 4 addresses */
0x30, /* start dependent functions, acceptable */
0x47, 0x01, 0x20, 0x06, 0x80, 0x06, 0x20, 0x04, /* I/O 0x620-0x680, decodes 16-bit, 32-byte alignment, 4 addresses */
0x38, /* end dependent functions */
0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */
0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */
0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */
0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
};
static uint8_t sb_awe32_pnp_rom[] = {
0x0e, 0x8c, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL0043, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
0x82, 0x15, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', ' ', 'A', 'W', 'E', '3', '2', ' ', 'P', 'n', 'P', /* ANSI identifier */
0x16, 0x0e, 0x8c, 0x00, 0x31, 0x00, 0xa9, /* logical device CTL0031, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */
0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */
0x31, 0x00, /* start dependent functions, preferred */
0x22, 0x20, 0x00, /* IRQ 5 */
0x2a, 0x02, 0x0c, /* DMA 1, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0x20, 0x16, /* DMA 5, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x20, 0x02, 0x01, 0x10, /* I/O 0x220, decodes 16-bit, 1-byte alignment, 16 addresses */
0x47, 0x01, 0x30, 0x03, 0x30, 0x03, 0x01, 0x02, /* I/O 0x330, decodes 16-bit, 1-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0xf8, 0x03, 0x01, 0x04, /* I/O 0x388-0x3F8, decodes 16-bit, 1-byte alignment, 4 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-byte alignment, 4 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x31, 0x02, /* start dependent functions, sub-optimal */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0x94, 0x03, 0x04, 0x04, /* I/O 0x388-0x394, decodes 16-bit, 4-byte alignment, 4 addresses */
0x38, /* end dependent functions */
0x16, 0x0e, 0x8c, 0x00, 0x21, 0x00, 0xa9, /* logical device CTL0021, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */
0x82, 0x09, 0x00, 'W', 'a', 'v', 'e', 'T', 'a', 'b', 'l', 'e', /* ANSI identifier */
0x31, 0x00, /* start dependent functions, preferred */
0x47, 0x01, 0x20, 0x06, 0x20, 0x06, 0x01, 0x04, /* I/O 0x620, decodes 16-bit, 1-byte alignment, 4 addresses */
0x47, 0x01, 0x20, 0x0a, 0x20, 0x0a, 0x01, 0x04, /* I/O 0xA20, decodes 16-bit, 1-byte alignment, 4 addresses */
0x47, 0x01, 0x20, 0x0e, 0x20, 0x0e, 0x01, 0x04, /* I/O 0xE20, decodes 16-bit, 1-byte alignment, 4 addresses */
0x30, /* start dependent functions, acceptable */
0x47, 0x01, 0x20, 0x06, 0x80, 0x06, 0x20, 0x04, /* I/O 0x620-0x680, decodes 16-bit, 32-byte alignment, 4 addresses */
0x47, 0x01, 0x20, 0x0a, 0x80, 0x0a, 0x20, 0x04, /* I/O 0xA20-0xA80, decodes 16-bit, 32-byte alignment, 4 addresses */
0x47, 0x01, 0x20, 0x0e, 0x80, 0x0e, 0x20, 0x04, /* I/O 0xE20-0xE80, decodes 16-bit, 32-byte alignment, 4 addresses */
0x38, /* end dependent functions */
0x15, 0x0e, 0x8c, 0x70, 0x01, 0x00, /* logical device CTL7001 */
0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */
0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */
0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
};
static uint8_t sb_awe64_gold_pnp_rom[] = {
0x0e, 0x8c, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL009E, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x20, /* PnP version 1.0, vendor version 2.0 */
0x82, 0x16, 0x00, 'C', 'r', 'e', 'a', 't', 'i', 'v', 'e', ' ', 'S', 'B', ' ', 'A', 'W', 'E', '6', '4', ' ', 'G', 'o', 'l', 'd', /* ANSI identifier */
0x16, 0x0e, 0x8c, 0x00, 0x44, 0x00, 0xa9, /* logical device CTL0044, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */
0x82, 0x05, 0x00, 'A', 'u', 'd', 'i', 'o', /* ANSI identifier */
0x31, 0x00, /* start dependent functions, preferred */
0x22, 0x20, 0x00, /* IRQ 5 */
0x2a, 0x02, 0x0c, /* DMA 1, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0x20, 0x16, /* DMA 5, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x20, 0x02, 0x01, 0x10, /* I/O 0x220, decodes 16-bit, 1-byte alignment, 16 addresses */
0x47, 0x01, 0x30, 0x03, 0x30, 0x03, 0x01, 0x02, /* I/O 0x330, decodes 16-bit, 1-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0xf8, 0x03, 0x01, 0x04, /* I/O 0x388-0x3F8, decodes 16-bit, 1-byte alignment, 4 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0xf8, 0x03, 0x01, 0x04, /* I/O 0x388-0x3F8, decodes 16-bit, 1-byte alignment, 4 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0xf8, 0x03, 0x01, 0x04, /* I/O 0x388-0x3F8, decodes 16-bit, 1-byte alignment, 4 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x30, /* start dependent functions, acceptable */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x31, 0x02, /* start dependent functions, sub-optimal */
0x22, 0xa0, 0x06, /* IRQ 5/7/9/10 */
0x2a, 0x0b, 0x0c, /* DMA 0/1/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */
0x2a, 0xe0, 0x16, /* DMA 5/6/7, compatibility, count by word, no count by byte, is bus master, 16-bit only */
0x47, 0x01, 0x20, 0x02, 0x80, 0x02, 0x20, 0x10, /* I/O 0x220-0x280, decodes 16-bit, 32-byte alignment, 16 addresses */
0x47, 0x01, 0x00, 0x03, 0x30, 0x03, 0x30, 0x02, /* I/O 0x300-0x330, decodes 16-bit, 48-byte alignment, 2 addresses */
0x47, 0x01, 0x88, 0x03, 0x94, 0x03, 0x04, 0x04, /* I/O 0x388-0x394, decodes 16-bit, 4-byte alignment, 4 addresses */
0x38, /* end dependent functions */
0x15, 0x0e, 0x8c, 0x70, 0x02, 0x00, /* logical device CTL7002 */
0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */
0x82, 0x04, 0x00, 'G', 'a', 'm', 'e', /* ANSI identifier */
0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x01, 0x08, /* I/O 0x200, decodes 16-bit, 1-byte alignment, 8 addresses */
0x16, 0x0e, 0x8c, 0x00, 0x23, 0x00, 0xa9, /* logical device CTL0023, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */
0x82, 0x09, 0x00, 'W', 'a', 'v', 'e', 'T', 'a', 'b', 'l', 'e', /* ANSI identifier */
0x31, 0x00, /* start dependent functions, preferred */
0x47, 0x01, 0x20, 0x06, 0x20, 0x06, 0x01, 0x04, /* I/O 0x620, decodes 16-bit, 1-byte alignment, 4 addresses */
0x47, 0x01, 0x20, 0x0a, 0x20, 0x0a, 0x01, 0x04, /* I/O 0xA20, decodes 16-bit, 1-byte alignment, 4 addresses */
0x47, 0x01, 0x20, 0x0e, 0x20, 0x0e, 0x01, 0x04, /* I/O 0xE20, decodes 16-bit, 1-byte alignment, 4 addresses */
0x30, /* start dependent functions, acceptable */
0x47, 0x01, 0x20, 0x06, 0x80, 0x06, 0x20, 0x04, /* I/O 0x620-0x680, decodes 16-bit, 32-byte alignment, 4 addresses */
0x47, 0x01, 0x20, 0x0a, 0x80, 0x0a, 0x20, 0x04, /* I/O 0xA20-0xA80, decodes 16-bit, 32-byte alignment, 4 addresses */
0x47, 0x01, 0x20, 0x0e, 0x80, 0x0e, 0x20, 0x04, /* I/O 0xE20-0xE80, decodes 16-bit, 32-byte alignment, 4 addresses */
0x38, /* end dependent functions */
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
};
#ifdef ENABLE_SB_LOG
@@ -1349,9 +1187,21 @@ sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv)
break;
case 1: /* Game */
case 1: /* IDE */
ide_pnp_config_changed(0, config, (void *) 2);
break;
case 2: /* Reserved (16) / WaveTable (32+) */
if (sb->dsp.sb_type > SB16)
emu8k_change_addr(&sb->emu8k, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
break;
case 3: /* Game */
gameport_remap(sb->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
break;
case 4: /* StereoEnhance (32) */
break;
}
}
@@ -1363,15 +1213,13 @@ sb_awe32_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pr
switch (ld) {
case 0: /* Audio */
sb_16_pnp_config_changed(0, config, sb);
break;
case 1: /* WaveTable */
emu8k_change_addr(&sb->emu8k, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
case 1: /* IDE */
sb_16_pnp_config_changed(ld, config, sb);
break;
case 2: /* Game */
sb_16_pnp_config_changed(1, config, sb);
case 3: /* WaveTable */
sb_16_pnp_config_changed(ld ^ 1, config, sb);
break;
}
}
@@ -1384,15 +1232,12 @@ sb_awe64_gold_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, voi
switch (ld) {
case 0: /* Audio */
sb_16_pnp_config_changed(0, config, sb);
case 2: /* WaveTable */
sb_16_pnp_config_changed(ld, config, sb);
break;
case 1: /* Game */
sb_16_pnp_config_changed(1, config, sb);
break;
case 2: /* WaveTable */
emu8k_change_addr(&sb->emu8k, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
sb_16_pnp_config_changed(3, config, sb);
break;
}
}
@@ -1722,12 +1567,11 @@ sb_pro_mcv_init(const device_t *info)
static void *
sb_pro_cs423x_init(const device_t *info)
sb_pro_compat_init(const device_t *info)
{
sb_t *sb = malloc(sizeof(sb_t));
memset(sb, 0, sizeof(sb_t));
sb->opl_enabled = 0; /* updated by cs423x code */
opl3_init(&sb->opl);
sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb);
@@ -1822,6 +1666,8 @@ sb_16_pnp_init(const device_t *info)
sb->gameport = gameport_add(&gameport_pnp_device);
device_add(&ide_ter_pnp_device);
isapnp_add_card(sb_16_pnp_rom, sizeof(sb_16_pnp_rom), sb_16_pnp_config_changed, NULL, NULL, NULL, sb);
return sb;
@@ -1835,6 +1681,27 @@ sb_awe32_available()
}
static int
sb_32_pnp_available()
{
return sb_awe32_available() && rom_present("roms/sound/CT3600 PnP.BIN");
}
static int
sb_awe32_pnp_available()
{
return sb_awe32_available() && rom_present("roms/sound/CT3980 PnP.BIN");
}
static int
sb_awe64_gold_available()
{
return sb_awe32_available() && rom_present("roms/sound/CT4540 PnP.BIN");
}
static void *
sb_awe32_init(const device_t *info)
{
@@ -1900,7 +1767,7 @@ sb_awe32_pnp_init(const device_t *info)
sb->opl_enabled = 1;
opl3_init(&sb->opl);
sb_dsp_init(&sb->dsp, ((info->local == 2) ? SBAWE64 : SBAWE32), SB_SUBTYPE_DEFAULT, sb);
sb_dsp_init(&sb->dsp, (info->local == 2) ? SBAWE64 : SBAWE32, SB_SUBTYPE_DEFAULT, sb);
sb_ct1745_mixer_reset(sb);
sb->mixer_enabled = 1;
@@ -1919,12 +1786,47 @@ sb_awe32_pnp_init(const device_t *info)
sb->gameport = gameport_add(&gameport_pnp_device);
if (info->local == 2)
isapnp_add_card(sb_awe64_gold_pnp_rom, sizeof(sb_awe64_gold_pnp_rom), sb_awe64_gold_pnp_config_changed, NULL, NULL, NULL, sb);
else if (info->local == 1)
isapnp_add_card(sb_32_pnp_rom, sizeof(sb_32_pnp_rom), sb_awe32_pnp_config_changed, NULL, NULL, NULL, sb);
else
isapnp_add_card(sb_awe32_pnp_rom, sizeof(sb_awe32_pnp_rom), sb_awe32_pnp_config_changed, NULL, NULL, NULL, sb);
if (info->local != 2)
device_add(&ide_ter_pnp_device);
char *pnp_rom_file = NULL;
switch (info->local) {
case 0:
pnp_rom_file = "roms/sound/CT3600 PnP.BIN";
break;
case 1:
pnp_rom_file = "roms/sound/CT3980 PnP.BIN";
break;
case 2:
pnp_rom_file = "roms/sound/CT4540 PnP.BIN";
break;
}
uint8_t *pnp_rom = NULL;
if (pnp_rom_file) {
FILE *f = rom_fopen(pnp_rom_file, "rb");
if (f) {
if (fread(sb->pnp_rom, 1, 512, f) == 512)
pnp_rom = sb->pnp_rom;
fclose(f);
}
}
switch (info->local) {
case 0:
isapnp_add_card(pnp_rom, sizeof(sb->pnp_rom), sb_16_pnp_config_changed, NULL, NULL, NULL, sb);
break;
case 1:
isapnp_add_card(pnp_rom, sizeof(sb->pnp_rom), sb_awe32_pnp_config_changed, NULL, NULL, NULL, sb);
break;
case 2:
isapnp_add_card(pnp_rom, sizeof(sb->pnp_rom), sb_awe64_gold_pnp_config_changed, NULL, NULL, NULL, sb);
break;
}
return sb;
}
@@ -2342,9 +2244,6 @@ static const device_config_t sb_32_pnp_config[] =
{
"None", 0
},
{
"512 KB", 512
},
{
"2 MB", 2048
},
@@ -2561,21 +2460,18 @@ static const device_config_t sb_awe64_gold_config[] =
{
"onboard_ram", "Onboard RAM", CONFIG_SELECTION, "", 4096, "", { 0 },
{
{
"None", 0
},
{
"512 KB", 512
},
{
"2 MB", 2048
},
{
"4 MB", 4096
},
{
"8 MB", 8192
},
{
"12 MB", 12288
},
{
"16 MB", 16384
},
{
"28 MB", 28*1024
},
@@ -2672,12 +2568,12 @@ const device_t sb_pro_mcv_device =
NULL
};
const device_t sb_pro_cs423x_device =
const device_t sb_pro_compat_device =
{
"Crystal CS423x Sound Blaster Pro compatibility",
"Sound Blaster Pro (Compatibility)",
DEVICE_ISA | DEVICE_AT,
0,
sb_pro_cs423x_init, sb_close, NULL, { NULL },
sb_pro_compat_init, sb_close, NULL, { NULL },
sb_speed_changed,
NULL,
NULL
@@ -2709,9 +2605,9 @@ const device_t sb_32_pnp_device =
{
"Sound Blaster 32 PnP",
DEVICE_ISA | DEVICE_AT,
1,
0,
sb_awe32_pnp_init, sb_awe32_close, NULL,
{ sb_awe32_available },
{ sb_32_pnp_available },
sb_speed_changed,
NULL,
sb_32_pnp_config
@@ -2734,9 +2630,9 @@ const device_t sb_awe32_pnp_device =
{
"Sound Blaster AWE32 PnP",
DEVICE_ISA | DEVICE_AT,
0,
1,
sb_awe32_pnp_init, sb_awe32_close, NULL,
{ sb_awe32_available },
{ sb_awe32_pnp_available },
sb_speed_changed,
NULL,
sb_awe32_pnp_config
@@ -2748,7 +2644,7 @@ const device_t sb_awe64_gold_device =
DEVICE_ISA | DEVICE_AT,
2,
sb_awe32_pnp_init, sb_awe32_close, NULL,
{ sb_awe32_available },
{ sb_awe64_gold_available },
sb_speed_changed,
NULL,
sb_awe64_gold_config

View File

@@ -37,6 +37,7 @@
#include <86box/snd_mpu401.h>
#include <86box/snd_sb_dsp.h>
#include <86box/snd_azt2316a.h>
#include <86box/snd_ac97.h>
#include <86box/filters.h>
@@ -109,6 +110,7 @@ static const SOUND_CARD sound_cards[] =
{ "sbmcv", &sb_mcv_device },
{ "sbpromcv", &sb_pro_mcv_device },
{ "es1371", &es1371_device },
{ "cs4297a", &cs4297a_device },
{ "", NULL }
};