Merge pull request #1470 from richardg867/feature/cs423x

Game port overhaul, Crystal CS423xB and other changes
This commit is contained in:
Miran Grča
2021-06-03 22:44:48 +02:00
committed by GitHub
38 changed files with 2143 additions and 907 deletions

View File

@@ -1278,7 +1278,6 @@ cpu_set(void)
break;
case CPU_CYRIX3S:
case CPU_EDEN: /* This until proper timings get discovered */
#ifdef USE_DYNAREC
x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f);
#else
@@ -2015,58 +2014,6 @@ cpu_CPUID(void)
break;
}
break;
case CPU_EDEN:
switch (EAX) {
case 0:
EAX = 1;
if (msr.fcr2 & (1 << 14)) {
EBX = msr.fcr3 >> 32;
ECX = msr.fcr3 & 0xffffffff;
EDX = msr.fcr2 >> 32;
} else {
EBX = 0x746e6543; /* CentaurHauls */
ECX = 0x736c7561;
EDX = 0x48727561;
}
break;
case 1:
EAX = CPUID;
EBX = ECX = 0;
EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MMX | CPUID_MTRR;
if (cpu_has_feature(CPU_FEATURE_CX8))
EDX |= CPUID_CMPXCHG8B;
break;
case 0x80000000:
EAX = 0x80000006;
break;
case 0x80000001:
EAX = CPUID;
EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_MMX | CPUID_MTRR | CPUID_3DNOW;
if (cpu_has_feature(CPU_FEATURE_CX8))
EDX |= CPUID_CMPXCHG8B;
break;
case 0x80000002: /* Processor name string */
case 0x80000003:
case 0x80000004:
EAX = 0x20414956; /* VIA Samuel 2 */
EBX = 0x756d6153;
ECX = 0x32206c65;
EDX = 0x00000000;
break;
case 0x80000005: /* Cache information */
EBX = 0x08800880; /* TLBs */
ECX = 0x40040120; /* L1 data cache */
EDX = 0x40020120; /* L1 instruction cache */
break;
case 0x80000006:
ECX = 0x40040120; /* L2 data cache */
break;
default:
EAX = EBX = ECX = EDX = 0;
break;
}
break;
}
}
@@ -2157,7 +2104,6 @@ cpu_RDMSR(void)
break;
case CPU_CYRIX3S:
case CPU_EDEN:
EAX = EDX = 0;
switch (ECX) {
case 0x10:
@@ -2609,7 +2555,6 @@ cpu_WRMSR(void)
break;
case CPU_CYRIX3S:
case CPU_EDEN:
switch (ECX) {
case 0x10:
tsc = EAX | ((uint64_t)EDX << 32);

View File

@@ -76,7 +76,6 @@ enum {
CPU_K6_2P,
CPU_K6_3P,
CPU_CYRIX3S,
CPU_EDEN,
CPU_PENTIUMPRO, /* 686 class CPUs */
CPU_PENTIUM2,
CPU_PENTIUM2D
@@ -247,7 +246,7 @@ typedef struct {
uint64_t ia32_pmc[8]; /* 0x000000c1 - 0x000000c8 */
uint64_t mtrr_cap; /* 0x000000fe */
/* IDT WinChip and WinChip 2 MSR's that are also on the VIA Cyrix III and Eden */
/* IDT WinChip and WinChip 2 MSR's that are also on the VIA Cyrix III */
uint32_t fcr; /* 0x00000107 (IDT), 0x00001107 (VIA) */
uint64_t fcr2, fcr3; /* 0x00000108 (IDT), 0x00001108 (VIA) */
@@ -266,7 +265,7 @@ typedef struct {
uint64_t ecx1e0; /* 0x000001e0 */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's that are also
on the VIA Cyrix III and Eden */
on the VIA Cyrix III */
uint64_t mtrr_physbase[8]; /* 0x00000200 - 0x0000020f */
uint64_t mtrr_physmask[8]; /* 0x00000200 - 0x0000020f (ECX & 1) */
uint64_t mtrr_fix64k_8000; /* 0x00000250 */
@@ -278,7 +277,7 @@ typedef struct {
uint64_t pat; /* 0x00000277 */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's that are also
on the VIA Cyrix III and Eden */
on the VIA Cyrix III */
uint64_t mtrr_deftype; /* 0x000002ff */
/* Pentium Pro, Pentium II Klamath, and Pentium II Deschutes MSR's */

View File

@@ -1036,17 +1036,6 @@ const cpu_family_t cpu_families[] = {
{"733", CPU_CYRIX3S, fpus_internal, 733333333, 5.5, 2050, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 66, 66, 18, 18, 88},
{"", 0}
}
}, {
.package = CPU_PKG_EBGA368,
.manufacturer = "VIA",
.name = "Eden Model 7",
.internal_name = "c3_eden",
.cpus = (const CPU[]) {
{"66", CPU_EDEN, fpus_internal, 66666666, 1.0, 2050, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 6, 6, 3, 3, 8}, /* out of spec */
{"100", CPU_EDEN, fpus_internal, 100000000, 1.0, 2050, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 9, 9, 4, 4, 12}, /* out of spec */
{"400", CPU_EDEN, fpus_internal, 400000000, 6.0, 2050, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 36, 36, 17, 17, 48},
{"600", CPU_EDEN, fpus_internal, 600000000, 6.0, 2050, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_FIXED_MULTIPLIER, 54, 54, 18, 18, 72},
}
}, {
.package = 0,
}

View File

@@ -776,7 +776,7 @@ lm78_init(const device_t *info)
/* National Semiconductor LM78 on ISA and SMBus. */
const device_t lm78_device = {
"National Semiconductor LM78 Hardware Monitor",
DEVICE_ISA | DEVICE_PCI,
DEVICE_ISA,
0x290 | LM78_I2C,
lm78_init, lm78_close, lm78_reset,
{ NULL }, NULL, NULL,
@@ -787,7 +787,7 @@ const device_t lm78_device = {
/* Winbond W83781D on ISA and SMBus. */
const device_t w83781d_device = {
"Winbond W83781D Hardware Monitor",
DEVICE_ISA | DEVICE_PCI,
DEVICE_ISA,
0x290 | LM78_I2C | LM78_W83781D,
lm78_init, lm78_close, lm78_reset,
{ NULL }, NULL, NULL,
@@ -799,7 +799,7 @@ const device_t w83781d_device = {
I2C-only W83781D clone with additional voltages, GPIOs and fan control. */
const device_t as99127f_device = {
"ASUS AS99127F Rev. 1 Hardware Monitor",
DEVICE_ISA | DEVICE_PCI,
DEVICE_ISA,
LM78_I2C | LM78_AS99127F_REV1,
lm78_init, lm78_close, lm78_reset,
{ NULL }, NULL, NULL,
@@ -810,7 +810,7 @@ const device_t as99127f_device = {
/* Rev. 2 is manufactured by Winbond and differs only in GPI registers. */
const device_t as99127f_rev2_device = {
"ASUS AS99127F Rev. 2 Hardware Monitor",
DEVICE_ISA | DEVICE_PCI,
DEVICE_ISA,
LM78_I2C | LM78_AS99127F_REV2,
lm78_init, lm78_close, lm78_reset,
{ NULL }, NULL, NULL,
@@ -821,7 +821,7 @@ const device_t as99127f_rev2_device = {
/* Winbond W83782D on ISA and SMBus. */
const device_t w83782d_device = {
"Winbond W83782D Hardware Monitor",
DEVICE_ISA | DEVICE_PCI,
DEVICE_ISA,
0x290 | LM78_I2C | LM78_W83782D,
lm78_init, lm78_close, lm78_reset,
{ NULL }, NULL, NULL,

View File

@@ -478,9 +478,7 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv)
isapnp_log("ISAPnP: Reset CSN\n");
card = dev->first_card;
while (card) {
card->csn = 0;
if (card->csn_changed)
card->csn_changed(card->csn, card->priv);
isapnp_set_csn(card, 0);
card = card->next;
}
}
@@ -506,9 +504,7 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv)
case 0x06: /* Card Select Number */
if (dev->isolated_card) {
isapnp_log("ISAPnP: Set CSN %02X\n", val);
dev->isolated_card->csn = val;
if (dev->isolated_card->csn_changed)
dev->isolated_card->csn_changed(dev->isolated_card->csn, dev->isolated_card->priv);
isapnp_set_csn(dev->isolated_card, val);
dev->isolated_card->state = PNP_STATE_CONFIG;
dev->isolated_card = NULL;
} else {
@@ -531,7 +527,7 @@ isapnp_write_data(uint16_t addr, uint8_t val, void *priv)
}
if (!ld)
fatal("ISAPnP: CSN %02X has no device %02X\n", card->csn, val);
isapnp_log("ISAPnP: CSN %02X has no device %02X\n", card->csn, val);
break;
@@ -685,8 +681,6 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size,
memset(card, 0, sizeof(isapnp_card_t));
card->enable = 1;
card->rom = rom;
card->rom_size = rom_size;
card->priv = priv;
card->config_changed = config_changed;
card->csn_changed = csn_changed;
@@ -702,6 +696,20 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size,
prev_card->next = card;
}
if (rom && rom_size)
isapnp_update_card_rom(card, rom, rom_size);
return card;
}
void
isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size)
{
isapnp_card_t *card = (isapnp_card_t *) priv;
card->rom = rom;
card->rom_size = rom_size;
/* Parse resources in ROM to allocate logical devices,
and determine the state of read-only register bits. */
#ifdef ENABLE_ISAPNP_LOG
@@ -709,11 +717,17 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size,
isapnp_log("ISAPnP: Parsing ROM resources for card %c%c%c%02X%02X (serial %08X)\n", '@' + ((vendor >> 10) & 0x1f), '@' + ((vendor >> 5) & 0x1f), '@' + (vendor & 0x1f), card->rom[2], card->rom[3], (card->rom[7] << 24) | (card->rom[6] << 16) | (card->rom[5] << 8) | card->rom[4]);
#endif
uint16_t i = 9, j;
uint8_t ldn = 0, res, in_df = 0;
uint8_t existing = 0, ldn = 0, res, in_df = 0;
uint8_t irq = 0, io = 0, mem_range = 0, mem_range_32 = 0, irq_df = 0, io_df = 0, mem_range_df = 0, mem_range_32_df = 0;
uint32_t len;
isapnp_device_t *ld = NULL, *prev_ld = NULL;
/* Check if this is an existing card which already has logical devices.
Any new logical devices will be added to the list after existing ones.
Removed LDs are not flushed as we may end up with an invalid ROM. */
existing = !!card->first_ld;
/* Iterate through ROM resources. */
while (i < card->rom_size) {
if (card->rom[i] & 0x80) { /* large resource */
res = card->rom[i] & 0x7f;
@@ -723,15 +737,29 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size,
case 0x01: /* memory range */
case 0x05: /* 32-bit memory range */
if (res == 0x01) {
if (mem_range > 3)
fatal("ISAPnP: Memory descriptor overflow (%d)\n", mem_range);
if (!ld) {
isapnp_log("ISAPnP: >>%s Memory descriptor with no logical device\n", in_df ? ">" : "");
break;
}
if (mem_range > 3) {
isapnp_log("ISAPnP: >>%s Memory descriptor overflow (%d)\n", in_df ? ">" : "", mem_range++);
break;
}
isapnp_log("ISAPnP: >>%s Memory range %d uses upper limit = ", in_df ? ">" : "", mem_range);
res = 1 << mem_range;
mem_range++;
} else {
if (mem_range_32 > 3)
fatal("ISAPnP: 32-bit memory descriptor overflow (%d)\n", mem_range_32);
if (!ld) {
isapnp_log("ISAPnP: >>%s 32-bit memory descriptor with no logical device\n", in_df ? ">" : "");
break;
}
if (mem_range_32 > 3) {
isapnp_log("ISAPnP: >>%s 32-bit memory descriptor overflow (%d)\n", in_df ? ">" : "", mem_range_32++);
break;
}
isapnp_log("ISAPnP: >>%s 32-bit memory range %d uses upper limit = ", in_df ? ">" : "", mem_range_32);
res = 1 << (4 + mem_range_32);
@@ -775,22 +803,39 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size,
#endif
/* We're done with the previous logical device. */
if (ld) {
prev_ld = ld;
if (ld && !existing)
isapnp_reset_ld_regs(ld);
/* Look for an existing logical device with this number,
and create one if none exist. */
if (existing) {
ld = card->first_ld;
while (ld && (ld->number != ldn))
ld = ld->next;
}
if (ld && (ld->number == ldn)) {
/* Reset some logical device state. */
ld->mem_upperlimit = ld->io_16bit = ld->irq_types = 0;
memset(ld->io_len, 0, sizeof(ld->io_len));
} else {
/* Create logical device. */
ld = (isapnp_device_t *) malloc(sizeof(isapnp_device_t));
memset(ld, 0, sizeof(isapnp_device_t));
/* Add to end of list. */
prev_ld = card->first_ld;
if (prev_ld) {
while (prev_ld->next)
prev_ld = prev_ld->next;
prev_ld->next = ld;
} else {
card->first_ld = ld;
}
}
/* Create logical device. */
ld = (isapnp_device_t *) malloc(sizeof(isapnp_device_t));
memset(ld, 0, sizeof(isapnp_device_t));
/* Set and increment logical device number. */
ld->number = ldn++;
if (prev_ld)
prev_ld->next = ld;
else
card->first_ld = ld;
/* Start the position counts over. */
irq = io = mem_range = mem_range_32 = irq_df = io_df = mem_range_df = mem_range_32_df = 0;
@@ -798,14 +843,26 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size,
#ifdef ENABLE_ISAPNP_LOG
case 0x03: /* compatible device ID */
if (!ld) {
isapnp_log("ISAPnP: >> Compatible device ID with no logical device\n");
break;
}
vendor = (card->rom[i + 1] << 8) | card->rom[i + 2];
isapnp_log("ISAPnP: >> Compatible device ID: %c%c%c%02X%02X\n", '@' + ((vendor >> 10) & 0x1f), '@' + ((vendor >> 5) & 0x1f), '@' + (vendor & 0x1f), card->rom[i + 3], card->rom[i + 4]);
break;
#endif
case 0x04: /* IRQ */
if (irq > 1)
fatal("ISAPnP: IRQ descriptor overflow (%d)\n", irq);
if (!ld) {
isapnp_log("ISAPnP: >>%s IRQ descriptor with no logical device\n", in_df ? ">" : "");
break;
}
if (irq > 1) {
isapnp_log("ISAPnP: >>%s IRQ descriptor overflow (%d)\n", in_df ? ">" : "", irq++);
break;
}
if (len == 2) /* default */
res = 0x01; /* high true edge sensitive */
@@ -822,6 +879,11 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size,
break;
case 0x06: /* start dependent function */
if (!ld) {
isapnp_log("ISAPnP: >> Start dependent function with no logical device\n");
break;
}
isapnp_log("ISAPnP: >> Start dependent function: %s\n", (((len == 0) || (card->rom[i + 1] == 1)) ? "acceptable" : ((card->rom[i + 1] == 0) ? "good" : ((card->rom[i + 1] == 2) ? "sub-optimal" : "unknown priority"))));
if (in_df) {
@@ -848,8 +910,15 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size,
break;
case 0x08: /* I/O port */
if (io > 7)
fatal("ISAPnP: I/O descriptor overflow (%d)\n", io);
if (!ld) {
isapnp_log("ISAPnP: >>%s I/O descriptor with no logical device\n", in_df ? ">" : "");
break;
}
if (io > 7) {
isapnp_log("ISAPnP: >>%s I/O descriptor overflow (%d)\n", in_df ? ">" : "", io++);
break;
}
isapnp_log("ISAPnP: >>%s I/O range %d %d-bit decode, %d ports\n", in_df ? ">" : "", io, (card->rom[i + 1] & 0x01) ? 16 : 10, card->rom[i + 7]);
@@ -873,6 +942,9 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size,
card->rom[i + 1] = -res;
isapnp_log("ISAPnP: End card resources (checksum %02X)\n", card->rom[i + 1]);
/* Stop parsing here. */
card->rom_size = i + 2;
break;
#ifdef ENABLE_ISAPNP_LOG
@@ -888,10 +960,8 @@ isapnp_add_card(uint8_t *rom, uint16_t rom_size,
}
/* We're done with the last logical device. */
if (ld)
if (ld && !existing)
isapnp_reset_ld_regs(ld);
return card;
}
@@ -904,13 +974,14 @@ isapnp_enable_card(void *priv, uint8_t enable)
/* Look for a matching card. */
isapnp_card_t *card = dev->first_card;
uint8_t will_enable;
while (card) {
if (card == priv) {
/* Enable or disable the card. */
card->enable = !!enable;
/* enable=2 is a cheat code to jump straight into CONFIG state. */
card->state = (enable == 2) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY;
will_enable = (enable >= ISAPNP_CARD_ENABLE);
if (will_enable ^ card->enable)
card->state = (enable == ISAPNP_CARD_FORCE_CONFIG) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY;
card->enable = will_enable;
/* Invalidate other references if we're disabling this card. */
if (!card->enable) {

View File

@@ -168,8 +168,8 @@ static uint8_t ide_qua_pnp_rom[] = {
0x47, 0x01, 0xee, 0x03, 0xee, 0x03, 0x01, 0x01, /* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 1 address */
0x30, /* start dependent functions, acceptable */
0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */
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, 0x01, /* I/O 0x36E, decodes 16-bit, 1-byte alignment, 1 address */
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, 0x01, /* I/O 0x3EE, decodes 16-bit, 1-byte alignment, 1 address */
0x30, /* start dependent functions, acceptable */
0x22, 0xb8, 0x1e, /* IRQ 3/4/5/7/9/10/11/12 */
0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08, /* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */

View File

@@ -1,10 +1,10 @@
/*
* VARCem Virtual ARchaeological Computer EMulator.
* An emulator of (mostly) x86-based PC systems and devices,
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
* spanning the era between 1981 and 1995.
* 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 VARCem Project.
* This file is part of the 86Box distribution.
*
* Implementation of a generic Game Port.
*
@@ -12,27 +12,11 @@
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
* RichardG, <richardg867@gmail.com>
*
* Copyright 2016-2018 Miran Grca.
* Copyright 2008-2018 Sarah Walker.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the:
*
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307
* USA.
* Copyright 2021 RichardG.
*/
#include <stdio.h>
#include <stdint.h>
@@ -45,6 +29,7 @@
#include <86box/device.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/isapnp.h>
#include <86box/gameport.h>
#include <86box/joystick_ch_flightstick_pro.h>
#include <86box/joystick_standard.h>
@@ -55,21 +40,26 @@
typedef struct {
pc_timer_t timer;
int axis_nr;
struct _gameport_ *gameport;
struct _joystick_instance_ *joystick;
} g_axis_t;
typedef struct _gameport_ {
uint8_t state;
uint16_t addr;
g_axis_t axis[4];
const joystick_if_t *joystick;
void *joystick_dat;
uint8_t len;
struct _joystick_instance_ *joystick;
struct _gameport_ *next;
} gameport_t;
typedef struct _joystick_instance_ {
uint8_t state;
g_axis_t axis[4];
int joystick_type = 0;
const joystick_if_t *intf;
void *dat;
} joystick_instance_t;
int joystick_type = 1;
static const joystick_if_t joystick_none = {
@@ -101,22 +91,54 @@ static const struct {
{ "thrustmaster_fcs", &joystick_tm_fcs },
{ "", NULL }
};
static gameport_t *gameport_global = NULL;
static joystick_instance_t *joystick_instance = NULL;
static uint8_t gameport_pnp_rom[] = {
0x09, 0xf8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, /* BOX0002, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
0x82, 0x09, 0x00, 'G', 'a', 'm', 'e', ' ', 'P', 'o', 'r', 't', /* ANSI identifier */
0x15, 0x09, 0xf8, 0x00, 0x02, 0x01, /* logical device BOX0002, can participate in boot */
0x1c, 0x41, 0xd0, 0xb0, 0x2f, /* compatible device PNPB02F */
0x31, 0x00, /* start dependent functions, preferred */
0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x200, decodes 16-bit, 8-byte alignment, 8 addresses */
0x30, /* start dependent functions, acceptable */
0x47, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */
0x31, 0x02, /* start dependent functions, sub-optimal */
0x47, 0x01, 0x00, 0x01, 0xf8, 0xff, 0x08, 0x08, /* I/O 0x100-0xFFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x38, /* end dependent functions */
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
};
static const isapnp_device_config_t gameport_pnp_defaults[] = {
{
.activate = 1,
.io = { { .base = 0x200 }, }
}
};
const device_t *standalone_gameport_type;
int gameport_instance_id = 0;
/* Linked list of active game ports. Only the top port responds to reads
or writes, and ports at the standard 200h location are prioritized. */
static gameport_t *active_gameports = NULL;
char *
joystick_get_name(int js)
{
if (! joysticks[js].joystick)
return(NULL);
return((char *)joysticks[js].joystick->name);
if (!joysticks[js].joystick)
return NULL;
return (char *) joysticks[js].joystick->name;
}
char *
joystick_get_internal_name(int js)
{
return((char *) joysticks[js].internal_name);
return (char *) joysticks[js].internal_name;
}
@@ -125,8 +147,7 @@ joystick_get_from_internal_name(char *s)
{
int c = 0;
while (strlen((char *) joysticks[c].internal_name))
{
while (strlen((char *) joysticks[c].internal_name)) {
if (!strcmp((char *) joysticks[c].internal_name, s))
return c;
c++;
@@ -139,62 +160,63 @@ joystick_get_from_internal_name(char *s)
int
joystick_get_max_joysticks(int js)
{
return(joysticks[js].joystick->max_joysticks);
return joysticks[js].joystick->max_joysticks;
}
int
joystick_get_axis_count(int js)
{
return(joysticks[js].joystick->axis_count);
return joysticks[js].joystick->axis_count;
}
int
joystick_get_button_count(int js)
{
return(joysticks[js].joystick->button_count);
return joysticks[js].joystick->button_count;
}
int
joystick_get_pov_count(int js)
{
return(joysticks[js].joystick->pov_count);
return joysticks[js].joystick->pov_count;
}
char *
joystick_get_axis_name(int js, int id)
{
return((char *)joysticks[js].joystick->axis_names[id]);
return (char *) joysticks[js].joystick->axis_names[id];
}
char *
joystick_get_button_name(int js, int id)
{
return((char *)joysticks[js].joystick->button_names[id]);
return (char *) joysticks[js].joystick->button_names[id];
}
char *
joystick_get_pov_name(int js, int id)
{
return (char *)joysticks[js].joystick->pov_names[id];
return (char *) joysticks[js].joystick->pov_names[id];
}
static void
gameport_time(gameport_t *gameport, int nr, int axis)
gameport_time(joystick_instance_t *joystick, int nr, int axis)
{
if (axis == AXIS_NOT_PRESENT)
timer_disable(&gameport->axis[nr].timer);
timer_disable(&joystick->axis[nr].timer);
else {
/* Convert axis value to 555 timing. */
axis += 32768;
axis = (axis * 100) / 65; /*Axis now in ohms*/
axis = (axis * 100) / 65; /* axis now in ohms */
axis = (axis * 11) / 1000;
timer_set_delay_u64(&gameport->axis[nr].timer, TIMER_USEC * (axis + 24)); /*max = 11.115 ms*/
timer_set_delay_u64(&joystick->axis[nr].timer, TIMER_USEC * (axis + 24)); /* max = 11.115 ms */
}
}
@@ -202,16 +224,23 @@ gameport_time(gameport_t *gameport, int nr, int axis)
static void
gameport_write(uint16_t addr, uint8_t val, void *priv)
{
gameport_t *p = (gameport_t *)priv;
gameport_t *dev = (gameport_t *) priv;
joystick_instance_t *joystick = dev->joystick;
p->state |= 0x0f;
/* Respond only if a joystick is present and this port is at the top of the active ports list. */
if (!joystick || (active_gameports != dev))
return;
gameport_time(p, 0, p->joystick->read_axis(p->joystick_dat, 0));
gameport_time(p, 1, p->joystick->read_axis(p->joystick_dat, 1));
gameport_time(p, 2, p->joystick->read_axis(p->joystick_dat, 2));
gameport_time(p, 3, p->joystick->read_axis(p->joystick_dat, 3));
p->joystick->write(p->joystick_dat);
/* Read all axes. */
joystick->state |= 0x0f;
gameport_time(joystick, 0, joystick->intf->read_axis(joystick->dat, 0));
gameport_time(joystick, 1, joystick->intf->read_axis(joystick->dat, 1));
gameport_time(joystick, 2, joystick->intf->read_axis(joystick->dat, 2));
gameport_time(joystick, 3, joystick->intf->read_axis(joystick->dat, 3));
/* Notify the interface. */
joystick->intf->write(joystick->dat);
cycles -= ISA_CYCLES(8);
}
@@ -220,120 +249,194 @@ gameport_write(uint16_t addr, uint8_t val, void *priv)
static uint8_t
gameport_read(uint16_t addr, void *priv)
{
gameport_t *p = (gameport_t *)priv;
uint8_t ret;
gameport_t *dev = (gameport_t *) priv;
joystick_instance_t *joystick = dev->joystick;
ret = p->state | p->joystick->read(p->joystick_dat);
/* Respond only if a joystick is present and this port is at the top of the active ports list. */
if (!joystick || (active_gameports != dev))
return 0xff;
/* Merge axis state with button state. */
uint8_t ret = joystick->state | joystick->intf->read(joystick->dat);
cycles -= ISA_CYCLES(8);
return(ret);
return ret;
}
static void
timer_over(void *priv)
{
g_axis_t *axis = (g_axis_t *)priv;
gameport_t *p = axis->gameport;
g_axis_t *axis = (g_axis_t *) priv;
p->state &= ~(1 << axis->axis_nr);
axis->joystick->state &= ~(1 << axis->axis_nr);
if (axis == &p->axis[0])
p->joystick->a0_over(p->joystick_dat);
/* Notify the joystick when the first axis' period is finished. */
if (axis == &axis->joystick->axis[0])
axis->joystick->intf->a0_over(axis->joystick->dat);
}
void
gameport_update_joystick_type(void)
{
gameport_t *p = gameport_global;
/* Add a standalone game port if a joystick is enabled but no other game ports exist. */
if (standalone_gameport_type)
gameport_add(standalone_gameport_type);
if (p != NULL) {
p->joystick->close(p->joystick_dat);
p->joystick = joysticks[joystick_type].joystick;
p->joystick_dat = p->joystick->init();
/* Reset the joystick interface. */
if (joystick_instance) {
joystick_instance->intf->close(joystick_instance->dat);
joystick_instance->intf = joysticks[joystick_type].joystick;
joystick_instance->dat = joystick_instance->intf->init();
}
}
void
gameport_remap(uint16_t address)
gameport_remap(void *priv, uint16_t address)
{
gameport_t *p = gameport_global;
if (!p)
gameport_t *dev = (gameport_t *) priv, *other_dev;
if (dev->addr) {
/* Remove this port from the active ports list. */
if (active_gameports == dev) {
active_gameports = dev->next;
dev->next = NULL;
} else {
other_dev = active_gameports;
while (other_dev) {
if (other_dev->next == dev) {
other_dev->next = dev->next;
dev->next = NULL;
break;
}
other_dev = other_dev->next;
}
}
io_removehandler(dev->addr, dev->len,
gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev);
}
dev->addr = address;
if (dev->addr) {
/* Add this port to the active ports list. */
if ((dev->addr & 0xfff8) == 0x200) {
/* Port within 200-207h: add to top. */
dev->next = active_gameports;
active_gameports = dev;
} else {
/* Port at other addresses: add to bottom. */
other_dev = active_gameports;
while (other_dev->next)
other_dev = other_dev->next;
other_dev->next = dev;
}
io_sethandler(dev->addr, dev->len,
gameport_read, NULL, NULL, gameport_write, NULL, NULL, dev);
}
}
static void
gameport_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv)
{
if (ld > 0)
return;
if (p->addr)
io_removehandler(p->addr, (p->addr & 1) ? 1 : 8,
gameport_read, NULL, NULL, gameport_write, NULL, NULL, p);
gameport_t *dev = (gameport_t *) priv;
p->addr = address;
/* Remap the game port to the specified address, or disable it. */
gameport_remap(dev, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
}
if (p->addr)
io_sethandler(p->addr, (p->addr & 1) ? 1 : 8,
gameport_read, NULL, NULL, gameport_write, NULL, NULL, p);
void *
gameport_add(const device_t *gameport_type)
{
/* Prevent a standalone game port from being added later on, unless this
is an unused Super I/O game port (no MACHINE_GAMEPORT machine flag). */
if (!(gameport_type->local & 0x1000000) || (machines[machine].flags & MACHINE_GAMEPORT))
standalone_gameport_type = NULL;
/* Add game port device. */
return device_add_inst(gameport_type, gameport_instance_id++);
}
static void *
gameport_init(const device_t *info)
{
gameport_t *p = NULL;
gameport_t *dev = NULL;
if (!joystick_type) {
gameport_global = p = NULL;
return(p);
dev = malloc(sizeof(gameport_t));
memset(dev, 0x00, sizeof(gameport_t));
/* Allocate global instance. */
if (!joystick_instance && joystick_type) {
joystick_instance = malloc(sizeof(joystick_instance_t));
memset(joystick_instance, 0x00, sizeof(joystick_instance_t));
joystick_instance->axis[0].joystick = joystick_instance;
joystick_instance->axis[1].joystick = joystick_instance;
joystick_instance->axis[2].joystick = joystick_instance;
joystick_instance->axis[3].joystick = joystick_instance;
joystick_instance->axis[0].axis_nr = 0;
joystick_instance->axis[1].axis_nr = 1;
joystick_instance->axis[2].axis_nr = 2;
joystick_instance->axis[3].axis_nr = 3;
timer_add(&joystick_instance->axis[0].timer, timer_over, &joystick_instance->axis[0], 0);
timer_add(&joystick_instance->axis[1].timer, timer_over, &joystick_instance->axis[1], 0);
timer_add(&joystick_instance->axis[2].timer, timer_over, &joystick_instance->axis[2], 0);
timer_add(&joystick_instance->axis[3].timer, timer_over, &joystick_instance->axis[3], 0);
joystick_instance->intf = joysticks[joystick_type].joystick;
joystick_instance->dat = joystick_instance->intf->init();
}
p = malloc(sizeof(gameport_t));
dev->joystick = joystick_instance;
memset(p, 0x00, sizeof(gameport_t));
/* Map game port to the default address. Not applicable on PnP-only ports. */
dev->len = (info->local >> 16) & 0xff;
gameport_remap(dev, info->local & 0xffff);
p->axis[0].gameport = p;
p->axis[1].gameport = p;
p->axis[2].gameport = p;
p->axis[3].gameport = p;
/* Register ISAPnP if this is a standard game port card. */
if (info->local == 0x200)
isapnp_set_device_defaults(isapnp_add_card(gameport_pnp_rom, sizeof(gameport_pnp_rom), gameport_pnp_config_changed, NULL, NULL, NULL, dev), 0, gameport_pnp_defaults);
p->axis[0].axis_nr = 0;
p->axis[1].axis_nr = 1;
p->axis[2].axis_nr = 2;
p->axis[3].axis_nr = 3;
timer_add(&p->axis[0].timer, timer_over, &p->axis[0], 0);
timer_add(&p->axis[1].timer, timer_over, &p->axis[1], 0);
timer_add(&p->axis[2].timer, timer_over, &p->axis[2], 0);
timer_add(&p->axis[3].timer, timer_over, &p->axis[3], 0);
p->joystick = joysticks[joystick_type].joystick;
p->joystick_dat = p->joystick->init();
gameport_global = p;
gameport_remap(info->local);
return(p);
return dev;
}
static void
gameport_close(void *priv)
{
gameport_t *p = (gameport_t *)priv;
gameport_t *dev = (gameport_t *) priv;
if (p == NULL) return;
/* If this port was active, remove it from the active ports list. */
gameport_remap(dev, 0);
p->joystick->close(p->joystick_dat);
/* Free the global instance here, if it wasn't already freed. */
if (joystick_instance) {
joystick_instance->intf->close(joystick_instance->dat);
gameport_global = NULL;
free(joystick_instance);
joystick_instance = NULL;
}
free(p);
free(dev);
}
const device_t gameport_device = {
"Game port",
0, 0x200,
0, 0x080200,
gameport_init,
gameport_close,
NULL, { NULL }, NULL,
@@ -342,7 +445,34 @@ const device_t gameport_device = {
const device_t gameport_201_device = {
"Game port (port 201h only)",
0, 0x201,
0, 0x010201,
gameport_init,
gameport_close,
NULL, { NULL }, NULL,
NULL
};
const device_t gameport_pnp_device = {
"Game port (Plug and Play only)",
0, 0x080000,
gameport_init,
gameport_close,
NULL, { NULL }, NULL,
NULL
};
const device_t gameport_pnp_6io_device = {
"Game port (Plug and Play only, 6 I/O ports)",
0, 0x060000,
gameport_init,
gameport_close,
NULL, { NULL }, NULL,
NULL
};
const device_t gameport_sio_device = {
"Game port (Super I/O)",
0, 0x1080000,
gameport_init,
gameport_close,
NULL, { NULL }, NULL,

View File

@@ -1,40 +1,22 @@
/*
* VARCem Virtual ARchaeological Computer EMulator.
* An emulator of (mostly) x86-based PC systems and devices,
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
* spanning the era between 1981 and 1995.
* 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 VARCem Project.
* This file is part of the 86Box distribution.
*
* Definitions for the generic game port handlers.
*
* NOTE: This module needs a good cleanup someday.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
* RichardG, <richardg867@gmail.com>
*
* Copyright 2016-2018 Miran Grca.
* Copyright 2008-2017 Sarah Walker.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the:
*
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307
* USA.
* Copyright 2008-2018 Sarah Walker.
* Copyright 2021 RichardG.
*/
#ifndef EMU_GAMEPORT_H
# define EMU_GAMEPORT_H
@@ -125,8 +107,13 @@ extern "C" {
#ifdef EMU_DEVICE_H
extern const device_t gameport_device;
extern const device_t gameport_201_device;
#endif
extern const device_t gameport_pnp_device;
extern const device_t gameport_pnp_6io_device;
extern const device_t gameport_sio_device;
extern const device_t *standalone_gameport_type;
#endif
extern int gameport_instance_id;
extern plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS];
extern joystick_t joystick_state[MAX_JOYSTICKS];
extern int joysticks_present;
@@ -150,7 +137,8 @@ extern char *joystick_get_button_name(int js, int id);
extern char *joystick_get_pov_name(int js, int id);
extern void gameport_update_joystick_type(void);
extern void gameport_remap(uint16_t address);
extern void gameport_remap(void *priv, uint16_t address);
extern void *gameport_add(const device_t *gameport_type);
#ifdef __cplusplus
}

View File

@@ -25,6 +25,13 @@
#define ISAPNP_DMA_DISABLED 4
enum {
ISAPNP_CARD_DISABLE = 0,
ISAPNP_CARD_ENABLE = 1,
ISAPNP_CARD_FORCE_CONFIG /* cheat code for UMC UM8669F */
};
typedef struct {
uint8_t activate;
struct {
@@ -51,6 +58,7 @@ void *isapnp_add_card(uint8_t *rom, uint16_t rom_size,
uint8_t (*read_vendor_reg)(uint8_t ld, uint8_t reg, void *priv),
void (*write_vendor_reg)(uint8_t ld, uint8_t reg, uint8_t val, void *priv),
void *priv);
void isapnp_update_card_rom(void *priv, uint8_t *rom, uint16_t rom_size);
void isapnp_enable_card(void *priv, uint8_t enable);
void isapnp_set_csn(void *priv, uint8_t csn);
void isapnp_set_device_defaults(void *priv, uint8_t ldn, const isapnp_device_config_t *config);

View File

@@ -61,6 +61,7 @@
#define MACHINE_SOUND 0x00008000 /* sys has int sound */
#define MACHINE_FDC 0x00010000 /* sys has int FDC */
#define MACHINE_NIC 0x00020000 /* sys has int NIC */
#define MACHINE_GAMEPORT 0x00040000 /* sys has int game port */
/* Combined flags. */
#define MACHINE_VIDEO_FIXED 0x00003000 /* sys has fixed int video */
/* Feature flags for internal storage controllers. */
@@ -110,7 +111,6 @@ enum {
MACHINE_TYPE_SLOT1_2,
MACHINE_TYPE_SLOT2,
MACHINE_TYPE_SOCKET370,
MACHINE_TYPE_EBGA368,
MACHINE_TYPE_MISC,
MACHINE_TYPE_MAX
};
@@ -564,9 +564,6 @@ extern int machine_at_603tcf_init(const machine_t *);
extern int machine_at_trinity371_init(const machine_t *);
extern int machine_at_p6bap_init(const machine_t *);
/* m_at_ebga368.c */
extern int machine_at_arb9673_init(const machine_t *);
/* m_at_misc.c */
extern int machine_at_vpc2007_init(const machine_t *);

View File

@@ -1,44 +1,63 @@
#define AD1848_TYPE_DEFAULT 0
#define AD1848_TYPE_CS4248 1
#define AD1848_TYPE_CS4231 2
/*
* 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.
*
* Definitions for AD1848 / CS4248 / CS4231 (Windows Sound System) codec emulation.
*
*
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* TheCollector1995, <mariogplayer@gmail.com>
* RichardG, <richardg867@gmail.com>
*
* Copyright 2008-2020 Sarah Walker.
* Copyright 2018-2020 TheCollector1995.
* Copyright 2021 RichardG.
*/
typedef struct ad1848_t
{
int index;
uint8_t regs[32]; /* 16 original + 16 CS4231A extensions */
uint8_t status;
int trd;
int mce;
int count;
int16_t out_l, out_r;
enum {
AD1848_TYPE_DEFAULT = 0,
AD1848_TYPE_CS4248,
AD1848_TYPE_CS4231,
AD1848_TYPE_CS4236
};
double cd_vol_l, cd_vol_r;
int enable;
typedef struct {
uint8_t type, index, xindex, regs[32], xregs[32], status; /* 16 original registers + 16 CS4231A extensions + 32 CS4236 extensions */
int irq, dma;
int freq;
pc_timer_t timer_count;
uint64_t timer_latch;
int count;
uint8_t trd, mce, wten: 1;
int16_t out_l, out_r;
double cd_vol_l, cd_vol_r;
int fm_vol_l, fm_vol_r;
uint8_t fmt_mask, wave_vol_mask;
int16_t buffer[SOUNDBUFLEN * 2];
int pos;
int type;
uint8_t enable: 1, irq: 4, dma: 3;
int freq;
pc_timer_t timer_count;
uint64_t timer_latch;
int16_t buffer[SOUNDBUFLEN * 2];
int pos;
} ad1848_t;
void ad1848_setirq(ad1848_t *ad1848, int irq);
void ad1848_setdma(ad1848_t *ad1848, int dma);
uint8_t ad1848_read(uint16_t addr, void *p);
void ad1848_write(uint16_t addr, uint8_t val, void *p);
extern void ad1848_setirq(ad1848_t *ad1848, int irq);
extern void ad1848_setdma(ad1848_t *ad1848, int dma);
extern void ad1848_updatevolmask(ad1848_t *ad1848);
void ad1848_update(ad1848_t *ad1848);
void ad1848_speed_changed(ad1848_t *ad1848);
extern uint8_t ad1848_read(uint16_t addr, void *priv);
extern void ad1848_write(uint16_t addr, uint8_t val, void *priv);
void ad1848_init(ad1848_t *ad1848, int type);
extern void ad1848_update(ad1848_t *ad1848);
extern void ad1848_speed_changed(ad1848_t *ad1848);
extern void ad1848_filter_cd_audio(int channel, double *buffer, void *priv);
extern void ad1848_init(ad1848_t *ad1848, uint8_t type);

View File

@@ -122,6 +122,7 @@ typedef struct sb_t
};
mpu_t *mpu;
emu8k_t emu8k;
void *gameport;
int pos;

View File

@@ -99,7 +99,7 @@ extern const device_t gus_device;
extern const device_t pas16_device;
#endif
/* PSSJ - What is this device? */
/* Tandy PSSJ */
extern const device_t pssj_device;
/* Creative Labs Sound Blaster */
@@ -110,6 +110,7 @@ extern const device_t sb_2_device;
extern const device_t sb_pro_v1_device;
extern const device_t sb_pro_v2_device;
extern const device_t sb_pro_mcv_device;
extern const device_t sb_pro_cs423x_device;
extern const device_t sb_16_device;
extern const device_t sb_16_pnp_device;
extern const device_t sb_32_pnp_device;
@@ -122,6 +123,11 @@ extern const device_t ssi2001_device;
/* Windows Sound System */
extern const device_t wss_device;
extern const device_t ncr_business_audio_device;
/* Crystal CS423x */
extern const device_t cs4236b_device;
extern const device_t cs4237b_device;
extern const device_t cs4238b_device;
#endif
#endif /*EMU_SOUND_H*/

View File

@@ -20,8 +20,7 @@ add_library(mch OBJECT machine.c machine_table.c m_xt.c m_xt_compaq.c
m_at_t3100e.c m_at_t3100e_vid.c m_ps1.c m_ps1_hdc.c m_ps2_isa.c
m_ps2_mca.c m_at_compaq.c m_at_286_386sx.c m_at_386dx_486.c
m_at_socket4_5.c m_at_socket7.c m_at_sockets7.c m_at_socket8.c
m_at_slot1.c m_at_slot2.c m_at_socket370.c m_at_ebga368.c
m_at_misc.c)
m_at_slot1.c m_at_slot2.c m_at_socket370.c m_at_misc.c)
if(HEDAKA)
target_compile_definitions(mch PRIVATE USE_HEDAKA)

View File

@@ -2516,8 +2516,7 @@ machine_amstrad_init(const machine_t *model, int type)
mouse_set_poll(ms_poll, ams);
}
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
}

View File

@@ -74,8 +74,7 @@ machine_at_common_init_ex(const machine_t *model, int type)
else if (type == 0)
device_add(&at_nvr_device);
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
}

View File

@@ -1,71 +0,0 @@
/*
* 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.
*
* Implementation of VIA EBGA368 Based Single Board Computers.
*
* Note: 86Box doesn't emulate all the components a SBC may have.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Tiseno100
*
* Copyright 2016-2019 Miran Grca.
* Copyright 2021 Tiseno100.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/mem.h>
#include <86box/io.h>
#include <86box/rom.h>
#include <86box/pci.h>
#include <86box/device.h>
#include <86box/chipset.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/keyboard.h>
#include <86box/flash.h>
#include <86box/sio.h>
#include <86box/hwm.h>
#include <86box/spd.h>
#include <86box/video.h>
#include "cpu.h"
#include <86box/machine.h>
int
machine_at_arb9673_init(const machine_t *model)
{
int ret;
ret = bios_load_linear("roms/machines/arb9673/W9673.v12",
0x00080000, 524288, 0);
if (bios_only || !ret)
return ret;
machine_at_common_init_ex(model, 2);
pci_init(PCI_CONFIG_TYPE_1);
pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4);
pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1);
pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4);
device_add(&via_vt8601_device);
device_add(&via_vt82c686b_device);
device_add(&via_vt82c686_sio_device);
device_add(&via_vt82c686_hwm_device);
device_add(&keyboard_ps2_ami_pci_device);
device_add(&sst_flash_39sf040_device);
spd_register(SPD_TYPE_SDRAM, 0xf, 32);
return ret;
}

View File

@@ -204,8 +204,8 @@ machine_at_p2bls_init(const machine_t *model)
pci_init(PCI_CONFIG_TYPE_1);
pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
pci_register_slot(0x04, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4);
pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3);
pci_register_slot(0x07, PCI_CARD_NORMAL, 3, 4, 1, 2);
pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); /* SCSI */
pci_register_slot(0x07, PCI_CARD_NORMAL, 3, 4, 1, 2); /* LAN */
pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1);
pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3);

View File

@@ -516,8 +516,7 @@ ps1_common_init(const machine_t *model)
device_add(&keyboard_ps2_ps1_device);
/* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */
if (joystick_type)
device_add(&gameport_201_device);
standalone_gameport_type = &gameport_201_device;
}

View File

@@ -1541,8 +1541,7 @@ machine_tandy1k_init(const machine_t *model, int type)
break;
}
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
eep_data_out = 0x0000;
}

View File

@@ -30,8 +30,7 @@ machine_xt_common_init(const machine_t *model)
device_add(&fdc_xt_device);
nmi_init();
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
}

View File

@@ -56,8 +56,7 @@ machine_xt_compaq_deskpro_init(const machine_t *model)
if (fdc_type == FDC_INTERNAL)
device_add(&fdc_xt_device);
nmi_init();
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
lpt1_remove();
lpt1_init(0x03bc);

View File

@@ -174,8 +174,7 @@ machine_xt_lxt3_init(const machine_t *model)
if (fdc_type == FDC_INTERNAL)
device_add(&fdc_xt_device);
nmi_init();
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
laserxt_init(1);

View File

@@ -738,8 +738,7 @@ machine_xt_m24_init(const machine_t *model)
/* FIXME: make sure this is correct?? */
device_add(&at_nvr_device);
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
nmi_init();

View File

@@ -155,8 +155,7 @@ machine_xt_philips_common_init(const machine_t *model)
nmi_init();
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
device_add(&keyboard_pc_device);

View File

@@ -181,8 +181,7 @@ machine_xt_xi8088_init(const machine_t *model)
nmi_init();
device_add(&ibmat_nvr_device);
pic2_init();
if (joystick_type)
device_add(&gameport_device);
standalone_gameport_type = &gameport_device;
return ret;
}

View File

@@ -34,6 +34,7 @@
#include <86box/rom.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/gameport.h>
#include "cpu.h"
#include <86box/video.h>
#include <86box/machine.h>
@@ -74,6 +75,8 @@ machine_init_ex(int m)
machine_log("Initializing as \"%s\"\n", machine_getname());
is_vpc = 0;
standalone_gameport_type = NULL;
gameport_instance_id = 0;
/* Set up the architecture flags. */
AT = IS_AT(machine);

View File

@@ -54,7 +54,6 @@ const machine_type_t machine_types[] = {
{ "Slot 1/2", MACHINE_TYPE_SLOT1_2 },
{ "Slot 2", MACHINE_TYPE_SLOT2 },
{ "Socket 370", MACHINE_TYPE_SOCKET370 },
{ "EBGA 368", MACHINE_TYPE_EBGA368 },
{ "Miscellaneous", MACHINE_TYPE_MISC }
};
@@ -340,7 +339,7 @@ const machine_t machines[] = {
{ "[i430VX] HP Brio 80xx", "brio80xx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 66666667, 66666667, 2200, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_brio80xx_init, NULL },
{ "[i430VX] Packard Bell PB680", "pb680", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2800, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_pb680_init, NULL },
{ "[i430VX] PC Partner MB520N", "mb520n", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2600, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_mb520n_init, NULL },
{ "[i430VX] Shuttle HOT-557", "430vx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 131072, 8192, 127, machine_at_i430vx_init, NULL },
{ "[i430VX] Shuttle HOT-557", "430vx", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 50000000, 66666667, 2500, 3520, 1.5, 3.0, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL | MACHINE_GAMEPORT, 8192, 131072, 8192, 127, machine_at_i430vx_init, NULL },
/* 430TX */
{ "[i430TX] ADLink NuPRO-592", "nupro592", MACHINE_TYPE_SOCKET7, CPU_PKG_SOCKET5_7, 0, 66666667, 66666667, 1900, 2800, 1.5, 5.5, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192, 262144, 8192, 255, machine_at_nupro592_init, NULL },
@@ -464,10 +463,6 @@ const machine_t machines[] = {
{ "[VIA Apollo Pro133A] Acorp 6VIA90AP", "6via90ap", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, MACHINE_MULTIPLIER_FIXED, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1572864, 8192, 255, machine_at_6via90ap_init, NULL },
{ "[VIA Apollo ProMedia] Jetway 603TCF", "603tcf", MACHINE_TYPE_SOCKET370, CPU_PKG_SOCKET370, 0, 66666667, 150000000, 1300, 3500, 1.5, 8.0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_603tcf_init, NULL },
/* EBGA368 machines */
/* VIA Apollo Pro */
{ "[VIA Apollo ProMedia] Acrosser AR-B9673","arb9673", MACHINE_TYPE_EBGA368, CPU_PKG_EBGA368, 0, 100000000, 133333333, 2050, 2050, MACHINE_MULTIPLIER_FIXED, MACHINE_PCI | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 131072, 131072, 0, 31, machine_at_arb9673_init, NULL },
/* Miscellaneous/Fake/Hypervisor machines */
{ "[i440BX] Microsoft Virtual PC 2007", "vpc2007", MACHINE_TYPE_MISC, CPU_PKG_SLOT1, CPU_BLOCK(CPU_PENTIUM2, CPU_CYRIX3S), 0, 0, 0, 0, 0, 0, MACHINE_AGP | MACHINE_BUS_PS2 | MACHINE_IDE_DUAL, 8192,1048576, 8192, 255, machine_at_vpc2007_init, NULL },

View File

@@ -709,7 +709,7 @@ trc_reset(uint8_t val)
{
if (val & 2) {
dma_reset();
device_reset_all_pci();
device_reset_all();
cpu_alt_reset = 0;

View File

@@ -39,7 +39,7 @@
#include <86box/isapnp.h>
/* This ROM is reconstructed out of the several assumptions, some of which are based on the IT8671F. */
/* This ROM is reconstructed out of several assumptions, some of which are based on the IT8671F. */
static uint8_t um8669f_pnp_rom[] = {
0x55, 0xa3, 0x86, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, /* UMC8669, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
@@ -89,7 +89,7 @@ static const isapnp_device_config_t um8669f_pnp_defaults[] = {
}, {
.activate = 0
}, {
.activate = 1,
.activate = 0,
.io = { { .base = 0x200 }, }
}
};
@@ -117,14 +117,15 @@ um8669f_log(const char *fmt, ...)
typedef struct um8669f_t
{
int locked, cur_reg_108;
void *pnp_card;
int locked, cur_reg_108;
void *pnp_card;
isapnp_device_config_t *pnp_config[5];
uint8_t regs_108[256];
uint8_t regs_108[256];
fdc_t *fdc;
serial_t *uart[2];
fdc_t *fdc;
serial_t *uart[2];
void *gameport;
} um8669f_t;
@@ -179,13 +180,13 @@ um8669f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pri
break;
case 5:
gameport_remap(0);
if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) {
um8669f_log("UM8669F: Game port enabled at port %04X\n", config->io[0].base);
gameport_remap(config->io[0].base);
} else
gameport_remap(dev->gameport, config->io[0].base);
} else {
um8669f_log("UM8669F: Game port disabled\n");
gameport_remap(dev->gameport, 0);
}
}
}
@@ -211,7 +212,7 @@ um8669f_write(uint16_t port, uint8_t val, void *priv)
if (dev->cur_reg_108 == 0xc1) {
um8669f_log("UM8669F: ISAPnP %sabled\n", (val & 0x80) ? "en" : "dis");
isapnp_enable_card(dev->pnp_card, (val & 0x80) ? 2 : 0);
isapnp_enable_card(dev->pnp_card, (val & 0x80) ? ISAPNP_CARD_FORCE_CONFIG : ISAPNP_CARD_DISABLE);
}
}
}
@@ -250,7 +251,7 @@ um8669f_reset(um8669f_t *dev)
lpt1_remove();
isapnp_enable_card(dev->pnp_card, 0);
isapnp_enable_card(dev->pnp_card, ISAPNP_CARD_DISABLE);
dev->locked = 1;
@@ -286,6 +287,8 @@ um8669f_init(const device_t *info)
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
dev->gameport = gameport_add(&gameport_sio_device);
io_sethandler(0x0108, 0x0002,
um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, dev);

View File

@@ -16,8 +16,8 @@
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
snd_lpt_dss.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c
snd_azt2316a.c snd_cms.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)
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)
if(FLUIDSYNTH)
target_compile_definitions(snd PRIVATE USE_FLUIDSYNTH)

View File

@@ -1,6 +1,23 @@
/*
AD1848 / CS4248 / CS4231 CODEC emulation (Windows Sound System compatible)*/
* 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.
*
* AD1848 / CS4248 / CS4231 (Windows Sound System) codec emulation.
*
*
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* TheCollector1995, <mariogplayer@gmail.com>
* RichardG, <richardg867@gmail.com>
*
* Copyright 2008-2020 Sarah Walker.
* Copyright 2018-2020 TheCollector1995.
* Copyright 2021 RichardG.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
@@ -13,292 +30,530 @@
#include <86box/sound.h>
#include <86box/snd_ad1848.h>
#define CS4231 0x80
static int ad1848_vols_6bits[64];
static double ad1848_vols_5bits_aux_gain[32];
#define CS4231 0x80
#define CS4236 0x03
void ad1848_setirq(ad1848_t *ad1848, int irq)
static int ad1848_vols_7bits[128];
static double ad1848_vols_5bits_aux_gain[32];
void
ad1848_setirq(ad1848_t *ad1848, int irq)
{
ad1848->irq = irq;
ad1848->irq = irq;
}
void ad1848_setdma(ad1848_t *ad1848, int dma)
void
ad1848_setdma(ad1848_t *ad1848, int dma)
{
ad1848->dma = dma;
ad1848->dma = dma;
}
uint8_t ad1848_read(uint16_t addr, void *p)
void
ad1848_updatevolmask(ad1848_t *ad1848)
{
ad1848_t *ad1848 = (ad1848_t *)p;
uint8_t temp = 0xff;
switch (addr & 3)
{
case 0: /*Index*/
temp = ad1848->index | ad1848->trd | ad1848->mce;
break;
case 1:
temp = ad1848->regs[ad1848->index];
if (ad1848->index == 0x0b) {
temp ^= 0x20;
ad1848->regs[ad1848->index] = temp;
if ((ad1848->type == AD1848_TYPE_CS4236) && ((ad1848->xregs[4] & 0x10) || ad1848->wten))
ad1848->wave_vol_mask = 0x3f;
else
ad1848->wave_vol_mask = 0x7f;
}
static void
ad1848_updatefreq(ad1848_t *ad1848)
{
double freq;
uint8_t set = 0;
if (ad1848->type == AD1848_TYPE_CS4236) {
if (ad1848->xregs[11] & 0x20) {
freq = 16934400LL;
switch (ad1848->xregs[13]) {
case 1: freq /= 353; break;
case 2: freq /= 529; break;
case 3: freq /= 617; break;
case 4: freq /= 1058; break;
case 5: freq /= 1764; break;
case 6: freq /= 2117; break;
case 7: freq /= 2558; break;
default: freq /= 16 * MAX(ad1848->xregs[13], 21); break;
}
break;
case 2:
temp = ad1848->status;
break;
}
return temp;
set = 1;
} else if (ad1848->regs[22] & 0x80) {
freq = (ad1848->regs[22] & 1) ? 33868800LL : 49152000LL;
set = (ad1848->regs[22] >> 1) & 0x3f;
switch (ad1848->regs[10] & 0x30) {
case 0x00: freq /= 128 * set; break;
case 0x10: freq /= 64 * set; break;
case 0x20: freq /= 256 * set; break;
}
set = 1;
}
}
if (!set) {
freq = (ad1848->regs[8] & 1) ? 16934400LL : 24576000LL;
switch ((ad1848->regs[8] >> 1) & 7) {
case 0: freq /= 3072; break;
case 1: freq /= 1536; break;
case 2: freq /= 896; break;
case 3: freq /= 768; break;
case 4: freq /= 448; break;
case 5: freq /= 384; break;
case 6: freq /= 512; break;
case 7: freq /= 2560; break;
}
}
ad1848->freq = freq;
ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq));
}
void ad1848_write(uint16_t addr, uint8_t val, void *p)
{
ad1848_t *ad1848 = (ad1848_t *)p;
double freq;
switch (addr & 3)
{
case 0: /*Index*/
if ((ad1848->regs[12] & 0x40) && (ad1848->type == AD1848_TYPE_CS4231))
ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */
else
ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */
ad1848->trd = val & 0x20;
ad1848->mce = val & 0x40;
break;
case 1:
switch (ad1848->index)
{
case 8:
freq = (val & 1) ? 16934400LL : 24576000LL;
switch ((val >> 1) & 7)
{
case 0: freq /= 3072; break;
case 1: freq /= 1536; break;
case 2: freq /= 896; break;
case 3: freq /= 768; break;
case 4: freq /= 448; break;
case 5: freq /= 384; break;
case 6: freq /= 512; break;
case 7: freq /= 2560; break;
}
ad1848->freq = freq;
ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq));
break;
case 9:
if (!ad1848->enable && (val & 0x41) == 0x01) {
if (ad1848->timer_latch)
timer_set_delay_u64(&ad1848->timer_count, ad1848->timer_latch);
else
timer_set_delay_u64(&ad1848->timer_count, TIMER_USEC);
}
ad1848->enable = ((val & 0x41) == 0x01);
if (!ad1848->enable) {
timer_disable(&ad1848->timer_count);
ad1848->out_l = ad1848->out_r = 0;
}
break;
case 11:
break;
case 12:
if (ad1848->type != AD1848_TYPE_DEFAULT)
ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80;
return;
case 14:
ad1848->count = ad1848->regs[15] | (val << 8);
break;
case 24:
if (! (val & 0x70))
ad1848->status &= 0xfe;
uint8_t
ad1848_read(uint16_t addr, void *priv)
{
ad1848_t *ad1848 = (ad1848_t *) priv;
uint8_t ret = 0xff;
switch (addr & 3) {
case 0: /* Index */
ret = ad1848->index | ad1848->trd | ad1848->mce;
break;
case 1:
ret = ad1848->regs[ad1848->index];
switch (ad1848->index) {
case 11:
ret ^= 0x20;
ad1848->regs[ad1848->index] = ret;
break;
case 18: case 19:
if (ad1848->type == AD1848_TYPE_CS4236) {
if ((ad1848->xregs[4] & 0x14) == 0x14) /* FM remapping */
ret = ad1848->xregs[ad1848->index - 12]; /* real FM volume on registers 6 and 7 */
else if (ad1848->wten && !(ad1848->xregs[4] & 0x08)) /* wavetable remapping */
ret = ad1848->xregs[ad1848->index - 2]; /* real wavetable volume on registers 16 and 17 */
}
break;
case 23:
if ((ad1848->type == AD1848_TYPE_CS4236) && (ad1848->regs[23] & 0x08)) {
if ((ad1848->xindex & 0xfe) == 0x00) /* remapped line volume */
ret = ad1848->regs[18 + ad1848->xindex];
else
ret = ad1848->xregs[ad1848->xindex];
}
break;
}
break;
case 2:
ret = ad1848->status;
break;
}
return ret;
}
void
ad1848_write(uint16_t addr, uint8_t val, void *priv)
{
ad1848_t *ad1848 = (ad1848_t *) priv;
uint8_t temp = 0, updatefreq = 0;
switch (addr & 3) {
case 0: /* Index */
if ((ad1848->regs[12] & 0x40) && (ad1848->type >= AD1848_TYPE_CS4231))
ad1848->index = val & 0x1f; /* cs4231a extended mode enabled */
else
ad1848->index = val & 0x0f; /* ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? */
if (ad1848->type == AD1848_TYPE_CS4236)
ad1848->regs[23] &= ~0x08; /* clear XRAE */
ad1848->trd = val & 0x20;
ad1848->mce = val & 0x40;
break;
case 1:
switch (ad1848->index) {
case 10:
if (ad1848->type != AD1848_TYPE_CS4236)
break;
/* fall-through */
case 8:
updatefreq = 1;
break;
case 9:
if (!ad1848->enable && (val & 0x41) == 0x01) {
if (ad1848->timer_latch)
timer_set_delay_u64(&ad1848->timer_count, ad1848->timer_latch);
else
timer_set_delay_u64(&ad1848->timer_count, TIMER_USEC);
}
ad1848->enable = ((val & 0x41) == 0x01);
if (!ad1848->enable) {
timer_disable(&ad1848->timer_count);
ad1848->out_l = ad1848->out_r = 0;
}
break;
case 11:
return;
case 12:
if (ad1848->type != AD1848_TYPE_DEFAULT)
ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80;
return;
case 14:
ad1848->count = ad1848->regs[15] | (val << 8);
break;
case 17:
if (ad1848->type >= AD1848_TYPE_CS4231) /* enable additional data formats on modes 2 and 3 */
ad1848->fmt_mask = (val & 0x40) ? 0xf0 : 0x70;
break;
case 18: case 19:
if (ad1848->type == AD1848_TYPE_CS4236) {
if ((ad1848->xregs[4] & 0x14) == 0x14) { /* FM remapping */
ad1848->xregs[ad1848->index - 12] = val; /* real FM volume on extended registers 6 and 7 */
temp = 1;
if (ad1848->index == 18) {
if (val & 0x80)
ad1848->fm_vol_l = 0;
else
ad1848->fm_vol_l = ad1848_vols_7bits[val & 0x3f];
} else {
if (val & 0x80)
ad1848->fm_vol_r = 0;
else
ad1848->fm_vol_r = ad1848_vols_7bits[val & 0x3f];
}
}
if (ad1848->wten && !(ad1848->xregs[4] & 0x08)) { /* wavetable remapping */
ad1848->xregs[ad1848->index - 2] = val; /* real wavetable volume on extended registers 16 and 17 */
temp = 1;
}
/* Stop here if any remapping is enabled. */
if (temp)
return;
/* HACK: the Windows 9x driver's "Synth" control writes to this
register with no remapping, even if internal FM is enabled. */
if (ad1848->index == 18) {
if (val & 0x80)
ad1848->fm_vol_l = 0;
else
ad1848->fm_vol_l = (int) ad1848_vols_5bits_aux_gain[val & 0x1f];
} else {
if (val & 0x80)
ad1848->fm_vol_r = 0;
else
ad1848->fm_vol_r = (int) ad1848_vols_5bits_aux_gain[val & 0x1f];
}
}
break;
case 22:
updatefreq = 1;
break;
case 23:
if ((ad1848->type == AD1848_TYPE_CS4236) && ((ad1848->regs[12] & 0x60) == 0x60)) {
if (!(ad1848->regs[23] & 0x08)) { /* existing (not new) XRAE is clear */
ad1848->xindex = ((val & 0x04) << 2) | (val >> 4);
break;
}
switch (ad1848->xindex) {
case 0: case 1: /* remapped line volume */
ad1848->regs[18 + ad1848->xindex] = val;
return;
case 6:
if (val & 0x80)
ad1848->fm_vol_l = 0;
else
ad1848->fm_vol_l = ad1848_vols_7bits[val & 0x3f];
break;
case 7:
if (val & 0x80)
ad1848->fm_vol_r = 0;
else
ad1848->fm_vol_r = ad1848_vols_7bits[val & 0x3f];
break;
case 11: case 13:
updatefreq = 1;
break;
case 25:
return;
}
ad1848->xregs[ad1848->xindex] = val;
if (updatefreq)
ad1848_updatefreq(ad1848);
return;
}
break;
case 24:
val = ad1848->regs[24] & ((val & 0x70) | 0x0f);
if (!(val & 0x70)) {
ad1848->status &= 0xfe;
picintc(1 << ad1848->irq);
}
break;
case 25:
return;
}
ad1848->regs[ad1848->index] = val;
if (updatefreq)
ad1848_updatefreq(ad1848);
if ((ad1848->type == AD1848_TYPE_CS4231) || (ad1848->type == AD1848_TYPE_CS4236)) { /* TODO: configure CD volume for CS4248/AD1848 too */
temp = (ad1848->type == AD1848_TYPE_CS4231) ? 18 : 4;
if (ad1848->regs[temp] & 0x80)
ad1848->cd_vol_l = 0;
else
ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f];
temp++;
if (ad1848->regs[temp] & 0x80)
ad1848->cd_vol_r = 0;
else
ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f];
}
break;
case 2:
ad1848->status &= 0xfe;
ad1848->regs[24] &= 0x0f;
break;
}
}
void
ad1848_speed_changed(ad1848_t *ad1848)
{
ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq));
}
void
ad1848_update(ad1848_t *ad1848)
{
for (; ad1848->pos < sound_pos_global; ad1848->pos++) {
ad1848->buffer[ad1848->pos*2] = ad1848->out_l;
ad1848->buffer[ad1848->pos*2 + 1] = ad1848->out_r;
}
}
static void
ad1848_poll(void *priv)
{
ad1848_t *ad1848 = (ad1848_t *) priv;
if (ad1848->timer_latch)
timer_advance_u64(&ad1848->timer_count, ad1848->timer_latch);
else
timer_advance_u64(&ad1848->timer_count, TIMER_USEC * 1000);
ad1848_update(ad1848);
if (ad1848->enable) {
int32_t temp;
switch (ad1848->regs[8] & ad1848->fmt_mask) {
case 0x00: /* Mono, 8-bit PCM */
ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256;
break;
case 25:
break;
}
ad1848->regs[ad1848->index] = val;
if (ad1848->type == AD1848_TYPE_CS4231) { /* TODO: configure CD volume for CS4248/AD1848 too */
if (ad1848->regs[0x12] & 0x80)
ad1848->cd_vol_l = 0;
else
ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f];
if (ad1848->regs[0x13] & 0x80)
ad1848->cd_vol_r = 0;
else
ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f];
}
break;
case 2:
ad1848->status &= 0xfe;
break;
}
}
void ad1848_speed_changed(ad1848_t *ad1848)
{
ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq));
}
void ad1848_update(ad1848_t *ad1848)
{
for (; ad1848->pos < sound_pos_global; ad1848->pos++)
{
ad1848->buffer[ad1848->pos*2] = ad1848->out_l;
ad1848->buffer[ad1848->pos*2 + 1] = ad1848->out_r;
}
}
static void ad1848_poll(void *p)
{
ad1848_t *ad1848 = (ad1848_t *)p;
if (ad1848->timer_latch)
timer_advance_u64(&ad1848->timer_count, ad1848->timer_latch);
else
timer_advance_u64(&ad1848->timer_count, TIMER_USEC * 1000);
ad1848_update(ad1848);
if (ad1848->enable)
{
int32_t temp;
switch (ad1848->regs[8] & 0x70)
{
case 0x00: /*Mono, 8-bit PCM*/
ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256;
break;
case 0x10: /*Stereo, 8-bit PCM*/
ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256;
ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256;
break;
case 0x40: /*Mono, 16-bit PCM*/
temp = dma_channel_read(ad1848->dma);
ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp;
break;
case 0x50: /*Stereo, 16-bit PCM*/
temp = dma_channel_read(ad1848->dma);
ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp;
temp = dma_channel_read(ad1848->dma);
ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp;
break;
}
if (ad1848->regs[6] & 0x80)
ad1848->out_l = 0;
else
ad1848->out_l = (ad1848->out_l * ad1848_vols_6bits[ad1848->regs[6] & 0x3f]) >> 16;
if (ad1848->regs[7] & 0x80)
ad1848->out_r = 0;
else
ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16;
if (ad1848->count < 0)
{
ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8);
if (!(ad1848->status & 0x01))
{
ad1848->status |= 0x01;
if (ad1848->regs[10] & 2)
picint(1 << ad1848->irq);
}
}
ad1848->count--;
}
else
{
ad1848->out_l = ad1848->out_r = 0;
ad1848->cd_vol_l = ad1848->cd_vol_r = 0;
}
}
static void ad1848_filter_cd_audio(int channel, double *buffer, void *p)
{
ad1848_t *ad1848 = (ad1848_t *)p;
double c;
double volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l;
c = ((*buffer) * volume) / 65536.0;
*buffer = c;
}
void ad1848_init(ad1848_t *ad1848, int type)
{
int c;
double attenuation;
ad1848->status = 0xcc;
ad1848->index = ad1848->trd = 0;
ad1848->mce = 0x40;
ad1848->regs[0] = ad1848->regs[1] = 0;
ad1848->regs[2] = ad1848->regs[3] = 0x80; /* Line-in */
ad1848->regs[4] = ad1848->regs[5] = 0x80;
ad1848->regs[6] = ad1848->regs[7] = 0x80; /* Left/right Output */
ad1848->regs[8] = 0;
ad1848->regs[9] = 0x08;
ad1848->regs[10] = ad1848->regs[11] = 0;
if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231))
ad1848->regs[12] = 0x8a;
else
ad1848->regs[12] = 0xa;
ad1848->regs[13] = 0;
ad1848->regs[14] = ad1848->regs[15] = 0;
if (type == AD1848_TYPE_CS4231)
{
ad1848->regs[16] = ad1848->regs[17] = 0;
ad1848->regs[18] = ad1848->regs[19] = 0x88;
ad1848->regs[22] = 0x80;
ad1848->regs[24] = 0;
ad1848->regs[25] = CS4231;
ad1848->regs[26] = 0x80;
ad1848->regs[29] = 0x80;
}
case 0x10: /* Stereo, 8-bit PCM */
ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256;
ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256;
break;
ad1848->out_l = 0;
ad1848->out_r = 0;
for (c = 0; c < 64; c++) {
attenuation = 0.0;
if (c & 0x01) attenuation -= 1.5;
if (c & 0x02) attenuation -= 3.0;
if (c & 0x04) attenuation -= 6.0;
if (c & 0x08) attenuation -= 12.0;
if (c & 0x10) attenuation -= 24.0;
if (c & 0x20) attenuation -= 48.0;
attenuation = pow(10, attenuation / 10);
ad1848_vols_6bits[c] = (int)(attenuation * 65536);
}
for (c = 0; c < 32; c++) {
attenuation = 12.0;
if (c & 0x01) attenuation -= 1.5;
if (c & 0x02) attenuation -= 3.0;
if (c & 0x04) attenuation -= 6.0;
if (c & 0x08) attenuation -= 12.0;
if (c & 0x10) attenuation -= 24.0;
case 0x40: /* Mono, 16-bit PCM little endian */
temp = dma_channel_read(ad1848->dma);
ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp;
break;
attenuation = pow(10, attenuation / 10);
case 0x50: /* Stereo, 16-bit PCM little endian */
temp = dma_channel_read(ad1848->dma);
ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp;
temp = dma_channel_read(ad1848->dma);
ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp;
break;
ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536);
}
ad1848->type = type;
timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0);
case 0xc0: /* Mono, 16-bit PCM big endian */
temp = dma_channel_read(ad1848->dma);
ad1848->out_l = ad1848->out_r = dma_channel_read(ad1848->dma) | (temp << 8);
break;
if (ad1848->type != AD1848_TYPE_DEFAULT && ad1848->type != AD1848_TYPE_CS4248)
sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848);
case 0xd0: /* Stereo, 16-bit PCM big endian */
temp = dma_channel_read(ad1848->dma);
ad1848->out_l = dma_channel_read(ad1848->dma) | (temp << 8);
temp = dma_channel_read(ad1848->dma);
ad1848->out_r = dma_channel_read(ad1848->dma) | (temp << 8);
break;
}
if (ad1848->regs[6] & 0x80)
ad1848->out_l = 0;
else
ad1848->out_l = (ad1848->out_l * ad1848_vols_7bits[ad1848->regs[6] & ad1848->wave_vol_mask]) >> 16;
if (ad1848->regs[7] & 0x80)
ad1848->out_r = 0;
else
ad1848->out_r = (ad1848->out_r * ad1848_vols_7bits[ad1848->regs[7] & ad1848->wave_vol_mask]) >> 16;
if (ad1848->count < 0) {
ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8);
if (!(ad1848->status & 0x01)) {
ad1848->status |= 0x01;
ad1848->regs[24] |= 0x10;
if (ad1848->regs[10] & 2)
picint(1 << ad1848->irq);
}
}
ad1848->count--;
} else {
ad1848->out_l = ad1848->out_r = 0;
ad1848->cd_vol_l = ad1848->cd_vol_r = 0;
}
}
void
ad1848_filter_cd_audio(int channel, double *buffer, void *priv)
{
ad1848_t *ad1848 = (ad1848_t *) priv;
double c;
double volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l;
c = ((*buffer) * volume) / 65536.0;
*buffer = c;
}
void
ad1848_init(ad1848_t *ad1848, uint8_t type)
{
uint8_t c;
double attenuation;
ad1848->status = 0xcc;
ad1848->index = ad1848->trd = 0;
ad1848->mce = 0x40;
ad1848->wten = 0;
ad1848->regs[0] = ad1848->regs[1] = 0;
ad1848->regs[2] = ad1848->regs[3] = 0x80; /* Line-in */
ad1848->regs[4] = ad1848->regs[5] = 0x80;
ad1848->regs[6] = ad1848->regs[7] = 0x80; /* Left/right Output */
ad1848->regs[8] = 0;
ad1848->regs[9] = 0x08;
ad1848->regs[10] = ad1848->regs[11] = 0;
if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231) || (type == AD1848_TYPE_CS4236))
ad1848->regs[12] = 0x8a;
else
ad1848->regs[12] = 0xa;
ad1848->regs[13] = 0;
ad1848->regs[14] = ad1848->regs[15] = 0;
if (type == AD1848_TYPE_CS4231) {
ad1848->regs[16] = ad1848->regs[17] = 0;
ad1848->regs[18] = ad1848->regs[19] = 0x88;
ad1848->regs[22] = 0x80;
ad1848->regs[24] = 0;
ad1848->regs[25] = CS4231;
ad1848->regs[26] = 0x80;
ad1848->regs[29] = 0x80;
} else if (type == AD1848_TYPE_CS4236) {
ad1848->regs[16] = ad1848->regs[17] = 0;
ad1848->regs[18] = ad1848->regs[19] = 0;
ad1848->regs[20] = ad1848->regs[21] = 0;
ad1848->regs[22] = ad1848->regs[23] = 0;
ad1848->regs[24] = 0;
ad1848->regs[25] = CS4236;
ad1848->regs[26] = 0xa0;
ad1848->regs[27] = ad1848->regs[29] = 0;
ad1848->regs[30] = ad1848->regs[31] = 0;
ad1848->xregs[0] = ad1848->xregs[1] = 0xe8;
ad1848->xregs[2] = ad1848->xregs[3] = 0xcf;
ad1848->xregs[4] = 0x84;
ad1848->xregs[5] = 0;
ad1848->xregs[6] = ad1848->xregs[7] = 0x80;
ad1848->xregs[8] = ad1848->xregs[9] = 0;
ad1848->xregs[10] = 0x3f;
ad1848->xregs[11] = 0xc0;
ad1848->xregs[14] = ad1848->xregs[15] = 0;
ad1848->xregs[16] = ad1848->xregs[17] = 0;
}
ad1848_updatefreq(ad1848);
ad1848->out_l = ad1848->out_r = 0;
ad1848->fm_vol_l = ad1848->fm_vol_r = 65536;
ad1848_updatevolmask(ad1848);
ad1848->fmt_mask = 0x70;
for (c = 0; c < 128; c++) {
attenuation = 0.0;
if (c & 0x40) {
if (c < 72) attenuation = (c - 72) * -1.5;
} else {
if (c & 0x01) attenuation -= 1.5;
if (c & 0x02) attenuation -= 3.0;
if (c & 0x04) attenuation -= 6.0;
if (c & 0x08) attenuation -= 12.0;
if (c & 0x10) attenuation -= 24.0;
if (c & 0x20) attenuation -= 48.0;
}
attenuation = pow(10, attenuation / 10);
ad1848_vols_7bits[c] = (int) (attenuation * 65536);
}
for (c = 0; c < 32; c++) {
attenuation = 12.0;
if (c & 0x01) attenuation -= 1.5;
if (c & 0x02) attenuation -= 3.0;
if (c & 0x04) attenuation -= 6.0;
if (c & 0x08) attenuation -= 12.0;
if (c & 0x10) attenuation -= 24.0;
attenuation = pow(10, attenuation / 10);
ad1848_vols_5bits_aux_gain[c] = (attenuation * 65536);
}
ad1848->type = type;
timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0);
if ((ad1848->type != AD1848_TYPE_DEFAULT) && (ad1848->type != AD1848_TYPE_CS4248))
sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848);
}

View File

@@ -8,6 +8,7 @@
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/gameport.h>
#include <86box/io.h>
#include <86box/nmi.h>
#include <86box/mem.h>
@@ -1352,13 +1353,16 @@ static void *es1371_init(const device_t *info)
sound_add_handler(es1371_get_buffer, es1371);
sound_set_cd_audio_filter(es1371_filter_cd_audio, es1371);
/* Add our own always-present game port to override the standalone ISAPnP one. */
gameport_remap(gameport_add(&gameport_pnp_device), 0x200);
es1371->card = pci_add_card(info->local ? PCI_ADD_SOUND : PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, es1371);
timer_add(&es1371->dac[1].timer, es1371_poll, es1371, 1);
generate_es1371_filter();
/* Return a CS4297A like VMWare does. */
/* Return a CS4297A like VMware does. */
es1371->codec_regs[0x7c] = 0x4352;
es1371->codec_regs[0x7e] = 0x5910;

829
src/sound/snd_cs423x.c Normal file
View File

@@ -0,0 +1,829 @@
/*
* 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.
*
* Crystal CS423x (SBPro/WSS compatible sound chips) emulation.
*
*
*
* Authors: RichardG, <richardg867@gmail.com>
*
* Copyright 2021 RichardG.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <math.h>
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/pic.h>
#include <86box/dma.h>
#include <86box/device.h>
#include <86box/gameport.h>
#include <86box/i2c.h>
#include <86box/isapnp.h>
#include <86box/sound.h>
#include <86box/midi.h>
#include <86box/snd_ad1848.h>
#include <86box/snd_opl.h>
#include <86box/snd_sb.h>
enum {
CRYSTAL_CS4236B = 0xcb,
CRYSTAL_CS4237B = 0xc8,
CRYSTAL_CS4238B = 0xc9
};
enum {
CRYSTAL_SLAM_NONE = 0,
CRYSTAL_SLAM_INDEX = 1,
CRYSTAL_SLAM_BYTE1 = 2,
CRYSTAL_SLAM_BYTE2 = 3
};
static const uint8_t slam_init_key[32] = { 0x96, 0x35, 0x9A, 0xCD, 0xE6, 0xF3, 0x79, 0xBC,
0x5E, 0xAF, 0x57, 0x2B, 0x15, 0x8A, 0xC5, 0xE2,
0xF1, 0xF8, 0x7C, 0x3E, 0x9F, 0x4F, 0x27, 0x13,
0x09, 0x84, 0x42, 0xA1, 0xD0, 0x68, 0x34, 0x1A };
static const uint8_t cs4236b_eeprom[] = {
/* Chip configuration */
0x55, 0xbb, /* magic */
0x00, 0x00, /* length */
0x00, 0x03, /* CD-ROM and modem decode */
0x80, /* misc. config */
0x80, /* global config */
0x0b, /* chip ID */
0x20, 0x04, 0x08, 0x10, 0x80, 0x00, 0x00, /* reserved */
0x00, /* external decode length */
0x48, /* reserved */
0x75, 0xb9, 0xfc, /* IRQ routing */
0x10, 0x03, /* DMA routing */
/* PnP resources */
0x0e, 0x63, 0x42, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, /* CSC4236, dummy checksum (filled in by isapnp_add_card) */
0x0a, 0x10, 0x01, /* PnP version 1.0, vendor version 0.1 */
0x82, 0x0e, 0x00, 'C', 'r', 'y', 's', 't', 'a', 'l', ' ', 'C', 'o', 'd', 'e' ,'c', 0x00, /* ANSI identifier */
0x15, 0x0e, 0x63, 0x00, 0x00, 0x00, /* logical device CSC0000 */
0x82, 0x07, 0x00, 'W', 'S', 'S', '/', 'S', 'B', 0x00, /* ANSI identifier */
0x31, 0x00, /* start dependent functions, preferred */
0x2a, 0x02, 0x28, /* DMA 1, type A, no count by word, count by byte, not bus master, 8-bit only */
0x2a, 0x09, 0x28, /* DMA 0/3, type A, no count by word, count by byte, not bus master, 8-bit only */
0x22, 0x20, 0x00, /* IRQ 5 */
0x47, 0x01, 0x34, 0x05, 0x34, 0x05, 0x04, 0x04, /* I/O 0x534, decodes 16-bit, 4-byte alignment, 4 addresses */
0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x08, 0x04, /* I/O 0x388, decodes 16-bit, 8-byte alignment, 4 addresses */
0x47, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x10, /* I/O 0x220, decodes 16-bit, 32-byte alignment, 16 addresses */
0x31, 0x01, /* start dependent functions, acceptable */
0x2a, 0x0a, 0x28, /* DMA 1/3, type A, no count by word, count by byte, not bus master, 8-bit only */
0x2a, 0x0b, 0x28, /* DMA 0/1/3, type A, no count by word, count by byte, not bus master, 8-bit only */
0x22, 0xa0, 0x9a, /* IRQ 5/7/9/11/12/15 */
0x47, 0x01, 0x34, 0x05, 0xfc, 0x0f, 0x04, 0x04, /* I/O 0x534-0xFFC, decodes 16-bit, 4-byte alignment, 4 addresses */
0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x08, 0x04, /* I/O 0x388, decodes 16-bit, 8-byte alignment, 4 addresses */
0x47, 0x01, 0x20, 0x02, 0x60, 0x02, 0x20, 0x10, /* I/O 0x220-0x260, decodes 16-bit, 32-byte alignment, 16 addresses */
0x31, 0x02, /* start dependent functions, sub-optimal */
0x2a, 0x0b, 0x28, /* DMA 0/1/3, type A, no count by word, count by byte, not bus master, 8-bit only */
0x22, 0xa0, 0x9a, /* IRQ 5/7/9/11/12/15 */
0x47, 0x01, 0x34, 0x05, 0xfc, 0x0f, 0x04, 0x04, /* I/O 0x534-0xFFC, decodes 16-bit, 4-byte alignment, 4 addresses */
0x47, 0x01, 0x88, 0x03, 0xf8, 0x03, 0x08, 0x04, /* I/O 0x388-0x3F8, decodes 16-bit, 8-byte alignment, 4 addresses */
0x47, 0x01, 0x20, 0x02, 0x00, 0x03, 0x20, 0x10, /* I/O 0x220-0x300, decodes 16-bit, 32-byte alignment, 16 addresses */
0x38, /* end dependent functions */
0x15, 0x0e, 0x63, 0x00, 0x01, 0x00, /* logical device CSC0001 */
0x82, 0x05, 0x00, 'G', 'A', 'M', 'E', 0x00, /* ANSI identifier */
0x31, 0x00, /* start dependent functions, preferred */
0x47, 0x01, 0x00, 0x02, 0x00, 0x02, 0x08, 0x08, /* I/O 0x200, decodes 16-bit, 8-byte alignment, 8 addresses */
0x31, 0x01, /* start dependent functions, acceptable */
0x47, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x08, /* I/O 0x208, decodes 16-bit, 8-byte alignment, 8 addresses */
0x38, /* end dependent functions */
0x15, 0x0e, 0x63, 0x00, 0x10, 0x00, /* logical device CSC0010 */
0x82, 0x05, 0x00, 'C', 'T', 'R', 'L', 0x00, /* ANSI identifier */
0x47, 0x01, 0x20, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x120-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */
0x15, 0x0e, 0x63, 0x00, 0x03, 0x00, /* logical device CSC0003 */
0x82, 0x04, 0x00, 'M', 'P', 'U', 0x00, /* ANSI identifier */
0x31, 0x00, /* start dependent functions, preferred */
0x22, 0x00, 0x02, /* IRQ 9 */
0x47, 0x01, 0x30, 0x03, 0x30, 0x03, 0x08, 0x02, /* I/O 0x330, decodes 16-bit, 8-byte alignment, 2 addresses */
0x31, 0x01, /* start dependent functions, acceptable */
0x22, 0x00, 0x9a, /* IRQ 9/11/12/15 */
0x47, 0x01, 0x30, 0x03, 0x60, 0x03, 0x08, 0x02, /* I/O 0x330-0x360, decodes 16-bit, 8-byte alignment, 2 addresses */
0x31, 0x02, /* start dependent functions, sub-optimal */
0x47, 0x01, 0x30, 0x03, 0xe0, 0x03, 0x08, 0x02, /* I/O 0x330-0x3E0, decodes 16-bit, 8-byte alignment, 2 addresses */
0x38, /* end dependent functions */
0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */
};
typedef struct cs423x_t
{
void *pnp_card;
ad1848_t ad1848;
sb_t *sb;
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;
uint8_t pnp_enable: 1, key_pos: 5, slam_enable: 1, slam_state: 2, slam_ld, slam_reg;
isapnp_device_config_t *slam_config;
} cs423x_t;
static void cs423x_slam_enable(cs423x_t *dev, uint8_t enable);
static void cs423x_pnp_enable(cs423x_t *dev, uint8_t update_rom, uint8_t update_hwconfig);
static void cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv);
static uint8_t
cs423x_read(uint16_t addr, void *priv)
{
cs423x_t *dev = (cs423x_t *) priv;
uint8_t reg = addr & 7;
uint8_t ret = dev->regs[reg];
switch (reg) {
case 1: /* EEPROM Interface */
ret &= ~0x04;
if ((dev->regs[1] & 0x04) && i2c_gpio_get_sda(dev->i2c))
ret |= 0x04;
break;
case 4: /* Control Indirect Data Register */
ret = dev->indirect_regs[dev->regs[3]];
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++;
}
break;
case 7: /* Global Status */
/* Context switching: take active context and interrupt flag, then clear interrupt flag. */
ret &= 0xc0;
dev->regs[7] &= 0x80;
if (dev->sb->mpu->state.irq_pending) /* MPU interrupt */
ret |= 0x08;
if (dev->ad1848.status & 0x01) /* WSS interrupt */
ret |= 0x10;
if (dev->sb->dsp.sb_irq8 || dev->sb->dsp.sb_irq16 || dev->sb->dsp.sb_irq401) /* SBPro interrupt */
ret |= 0x20;
break;
}
return ret;
}
static void
cs423x_write(uint16_t addr, uint8_t val, void *priv)
{
cs423x_t *dev = (cs423x_t *) priv;
uint8_t reg = addr & 0x07;
switch (reg) {
case 1: /* EEPROM Interface */
if (val & 0x04)
i2c_gpio_set(dev->i2c, val & 0x01, val & 0x02);
break;
case 3: /* Control Indirect Access Register */
val &= 0x0f;
break;
case 4: /* Control Indirect Data Register */
switch (dev->regs[3] & 0x0f) {
case 0: /* WSS Master Control */
if (val & 0x80)
ad1848_init(&dev->ad1848, dev->ad1848_type);
val = 0x00;
break;
case 1: /* Version / Chip ID */
case 7: /* Reserved */
case 9 ... 15: /* unspecified */
return;
case 2: /* 3D Space and {Center|Volume} */
case 6: /* Upper Channel Status */
if (dev->type < CRYSTAL_CS4237B)
return;
break;
case 3: /* 3D Enable */
if (dev->type < CRYSTAL_CS4237B)
return;
val &= 0xe0;
break;
case 4: /* Consumer Serial Port Enable */
if (dev->type < CRYSTAL_CS4237B)
return;
val &= 0xf0;
break;
case 5: /* Lower Channel Status */
if (dev->type < CRYSTAL_CS4237B)
return;
val &= 0xfe;
break;
case 8: /* CS9236 Wavetable Control */
val &= 0x0f;
cs423x_pnp_enable(dev, 0, 0);
/* Update WTEN state on the WSS codec. */
dev->ad1848.wten = !!(val & 0x08);
ad1848_updatevolmask(&dev->ad1848);
break;
}
dev->indirect_regs[dev->regs[3]] = val;
break;
case 5: /* Control/RAM Access */
switch (dev->ram_dl) {
case 0: /* commands */
switch (val) {
case 0x55: /* Disable PnP Key */
dev->pnp_enable = 0;
/* fall-through */
case 0x5a: /* Update Hardware Configuration Data */
cs423x_pnp_enable(dev, 0, 1);
break;
case 0x56: /* Disable Crystal Key */
cs423x_slam_enable(dev, 0);
break;
case 0x57: /* Jump to ROM */
break;
case 0xaa: /* Download RAM */
dev->ram_dl = 1;
break;
}
break;
case 1: /* low address byte */
dev->ram_addr = val;
dev->ram_dl++;
break;
case 2: /* high address byte */
dev->ram_addr |= (val << 8);
dev->ram_dl++;
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++;
break;
}
break;
case 6: /* RAM Access End */
if (!val) {
dev->ram_dl = 0;
/* Update PnP state and resource data. */
cs423x_pnp_enable(dev, 1, 0);
}
break;
case 7: /* Global Status */
return;
}
dev->regs[reg] = val;
}
static void
cs423x_slam_write(uint16_t addr, uint8_t val, void *priv)
{
cs423x_t *dev = (cs423x_t *) priv;
uint8_t idx;
switch (dev->slam_state) {
case CRYSTAL_SLAM_NONE:
/* Not in SLAM: read and compare Crystal key. */
if (val == slam_init_key[dev->key_pos]) {
dev->key_pos++;
/* Was the key successfully written? */
if (!dev->key_pos) {
/* Discard any pending logical device configuration, just to be safe. */
if (dev->slam_config) {
free(dev->slam_config);
dev->slam_config = NULL;
}
/* Enter SLAM. */
dev->slam_state = CRYSTAL_SLAM_INDEX;
}
} else {
dev->key_pos = 0;
}
break;
case CRYSTAL_SLAM_INDEX:
/* Write register index. */
dev->slam_reg = val;
dev->slam_state = CRYSTAL_SLAM_BYTE1;
break;
case CRYSTAL_SLAM_BYTE1:
case CRYSTAL_SLAM_BYTE2:
/* Write register value: two bytes for I/O ports, single byte otherwise. */
switch (dev->slam_reg) {
case 0x06: /* Card Select Number */
isapnp_set_csn(dev->pnp_card, val);
break;
case 0x15: /* Logical Device ID */
/* Apply the previous logical device's configuration, and reuse its config structure. */
if (dev->slam_config)
cs423x_pnp_config_changed(dev->slam_ld, dev->slam_config, dev);
else
dev->slam_config = (isapnp_device_config_t *) malloc(sizeof(isapnp_device_config_t));
/* Start new logical device. */
memset(dev->slam_config, 0, sizeof(isapnp_device_config_t));
dev->slam_ld = val;
break;
case 0x47: /* I/O Port Base Address 0 */
case 0x48: /* I/O Port Base Address 1 */
case 0x42: /* I/O Port Base Address 2 */
idx = (dev->slam_reg == 0x42) ? 2 : (dev->slam_reg - 0x47);
if (dev->slam_state == CRYSTAL_SLAM_BYTE1) {
/* Set high byte, or ignore it if no logical device is selected. */
if (dev->slam_config)
dev->slam_config->io[idx].base = val << 8;
/* Prepare for the second (low byte) write. */
dev->slam_state = CRYSTAL_SLAM_BYTE2;
return;
} else if (dev->slam_config) {
/* Set low byte, or ignore it if no logical device is selected. */
dev->slam_config->io[idx].base |= val;
}
break;
case 0x22: /* Interrupt Select 0 */
case 0x27: /* Interrupt Select 1 */
/* Stop if no logical device is selected. */
if (!dev->slam_config)
break;
/* Set IRQ value. */
idx = (dev->slam_reg == 0x22) ? 0 : 1;
dev->slam_config->irq[idx].irq = val & 15;
break;
case 0x2a: /* DMA Select 0 */
case 0x25: /* DMA Select 1 */
/* Stop if no logical device is selected. */
if (!dev->slam_config)
break;
/* Set DMA value. */
idx = (dev->slam_reg == 0x2a) ? 0 : 1;
dev->slam_config->dma[idx].dma = val & 7;
break;
case 0x33: /* Activate Device */
/* Stop if no logical device is selected. */
if (!dev->slam_config)
break;
/* Activate or deactivate the device. */
dev->slam_config->activate = val & 0x01;
break;
case 0x79: /* activate chip */
/* Apply the last logical device's configuration. */
if (dev->slam_config) {
cs423x_pnp_config_changed(dev->slam_ld, dev->slam_config, dev);
free(dev->slam_config);
dev->slam_config = NULL;
}
/* Exit out of SLAM. */
dev->slam_state = CRYSTAL_SLAM_NONE;
break;
}
/* Prepare for the next register, unless a two-byte read returns above. */
dev->slam_state = CRYSTAL_SLAM_INDEX;
break;
}
}
static void
cs423x_slam_enable(cs423x_t *dev, uint8_t enable)
{
/* Disable SLAM. */
if (dev->slam_enable) {
dev->slam_state = CRYSTAL_SLAM_NONE;
dev->slam_enable = 0;
io_removehandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev);
}
/* Enable SLAM if the CKD bit is not set. */
if (enable && !(dev->ram_data[2] & 0x10)) {
dev->slam_enable = 1;
io_sethandler(0x279, 1, NULL, NULL, NULL, cs423x_slam_write, NULL, NULL, dev);
}
}
static void
cs423x_ctxswitch_write(uint16_t addr, uint8_t val, void *priv)
{
cs423x_t *dev = (cs423x_t *) priv;
uint8_t ctx = (dev->regs[7] & 0x80),
enable_opl = (dev->ad1848.xregs[4] & 0x10) && !(dev->indirect_regs[2] & 0x85);
/* Check if a context switch (WSS=1 <-> SBPro=0) occurred through the address being written. */
if ((dev->regs[7] & 0x80) ? ((addr & 0xfff0) == dev->sb_base) : ((addr & 0xfffc) == dev->wss_base)) {
/* Flip context bit. */
dev->regs[7] ^= 0x80;
ctx ^= 0x80;
/* Update CD audio filter.
FIXME: not thread-safe: filter function TOCTTOU in sound_cd_thread! */
sound_set_cd_audio_filter(NULL, NULL);
if (ctx) /* WSS */
sound_set_cd_audio_filter(ad1848_filter_cd_audio, &dev->ad1848);
else /* SBPro */
sound_set_cd_audio_filter(sbpro_filter_cd_audio, dev->sb);
/* Fire a context switch interrupt if enabled. */
if ((dev->regs[0] & 0x20) && (dev->ad1848.irq > 0)) {
dev->regs[7] |= 0x40; /* set interrupt flag */
picint(1 << dev->ad1848.irq); /* control device shares IRQ with WSS and SBPro */
}
}
/* Update OPL ownership and state regardless of context switch,
to trap writes to other registers which may disable the OPL. */
dev->sb->opl_enabled = !ctx && enable_opl;
dev->opl_wss = ctx && enable_opl;
}
static void
cs423x_get_buffer(int32_t *buffer, int len, void *priv)
{
cs423x_t *dev = (cs423x_t *) priv;
int c, opl_wss = dev->opl_wss;
/* Output audio from the WSS codec, and also the OPL if we're in charge of it. */
ad1848_update(&dev->ad1848);
if (opl_wss)
opl3_update(&dev->sb->opl);
/* Don't output anything if the analog section is powered down. */
if (!(dev->indirect_regs[2] & 0xa4)) {
for (c = 0; c < len * 2; c += 2) {
if (opl_wss) {
buffer[c] += (dev->sb->opl.buffer[c] * dev->ad1848.fm_vol_l) >> 16;
buffer[c + 1] += (dev->sb->opl.buffer[c + 1] * dev->ad1848.fm_vol_r) >> 16;
}
buffer[c] += dev->ad1848.buffer[c] / 2;
buffer[c + 1] += dev->ad1848.buffer[c + 1] / 2;
}
}
dev->ad1848.pos = 0;
if (opl_wss)
dev->sb->opl.pos = 0;
}
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);
/* Update PnP state. */
isapnp_enable_card(dev->pnp_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) {
dev->indirect_regs[8] |= 0x08;
dev->ad1848.wten = 1;
} else {
dev->indirect_regs[8] &= ~0x08;
dev->ad1848.wten = 0;
}
/* Update SPS. */
if (dev->ram_data[3] & 0x04)
dev->indirect_regs[8] |= 0x04;
else
dev->indirect_regs[8] &= ~0x04;
/* Update IFM. */
if (dev->ram_data[3] & 0x80)
dev->ad1848.xregs[4] |= 0x10;
else
dev->ad1848.xregs[4] &= ~0x10;
/* Inform WSS codec of the changes. */
ad1848_updatevolmask(&dev->ad1848);
}
}
static void
cs423x_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv)
{
cs423x_t *dev = (cs423x_t *) priv;
switch (ld) {
case 0: /* WSS, OPL3 and SBPro */
if (dev->wss_base) {
io_removehandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848);
io_removehandler(dev->wss_base, 4, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev);
dev->wss_base = 0;
}
if (dev->opl_base) {
io_removehandler(dev->opl_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl);
dev->opl_base = 0;
}
if (dev->sb_base) {
sb_dsp_setaddr(&dev->sb->dsp, 0);
io_removehandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl);
io_removehandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl);
io_removehandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb);
io_removehandler(dev->sb_base, 16, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev);
dev->sb_base = 0;
}
ad1848_setirq(&dev->ad1848, 0);
sb_dsp_setirq(&dev->sb->dsp, 0);
ad1848_setdma(&dev->ad1848, 0);
sb_dsp_setdma8(&dev->sb->dsp, 0);
if (config->activate) {
if (config->io[0].base != ISAPNP_IO_DISABLED) {
dev->wss_base = config->io[0].base;
io_sethandler(dev->wss_base, 4, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &dev->ad1848);
io_sethandler(dev->wss_base, 4, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev);
}
if (config->io[1].base != ISAPNP_IO_DISABLED) {
dev->opl_base = config->io[1].base;
io_sethandler(dev->opl_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl);
}
if (config->io[2].base != ISAPNP_IO_DISABLED) {
dev->sb_base = config->io[2].base;
sb_dsp_setaddr(&dev->sb->dsp, dev->sb_base);
io_sethandler(dev->sb_base, 4, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl);
io_sethandler(dev->sb_base + 8, 2, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &dev->sb->opl);
io_sethandler(dev->sb_base + 4, 2, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, dev->sb);
io_sethandler(dev->sb_base, 16, NULL, NULL, NULL, cs423x_ctxswitch_write, NULL, NULL, dev);
}
if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) {
ad1848_setirq(&dev->ad1848, config->irq[0].irq);
sb_dsp_setirq(&dev->sb->dsp, config->irq[0].irq);
}
if (config->dma[0].dma != ISAPNP_DMA_DISABLED) {
ad1848_setdma(&dev->ad1848, config->dma[0].dma);
sb_dsp_setdma8(&dev->sb->dsp, config->dma[0].dma);
}
}
break;
case 1: /* Game Port */
if (dev->gameport)
gameport_remap(dev->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
break;
case 2: /* Control Registers */
if (dev->ctrl_base) {
io_removehandler(dev->ctrl_base, 8, cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, dev);
dev->ctrl_base = 0;
}
if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) {
dev->ctrl_base = config->io[0].base;
io_sethandler(dev->ctrl_base, 8, cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, dev);
}
break;
case 3: /* MPU-401 */
mpu401_change_addr(dev->sb->mpu, 0);
mpu401_setirq(dev->sb->mpu, 0);
if (config->activate) {
if (config->io[0].base != ISAPNP_IO_DISABLED)
mpu401_change_addr(dev->sb->mpu, config->io[0].base);
if (config->irq[0].irq != ISAPNP_IRQ_DISABLED)
mpu401_setirq(dev->sb->mpu, config->irq[0].irq);
}
break;
}
}
static void
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));
/* Reset registers. */
memset(dev->indirect_regs, 0, sizeof(dev->indirect_regs));
dev->indirect_regs[1] = dev->type;
if (dev->type == CRYSTAL_CS4238B)
dev->indirect_regs[2] = 0x20;
/* Reset WSS codec. */
ad1848_init(&dev->ad1848, dev->ad1848_type);
/* Reset PnP resource data, state and logical devices. */
dev->pnp_enable = 1;
cs423x_pnp_enable(dev, 1, 1);
if (dev->pnp_card)
isapnp_reset_card(dev->pnp_card);
/* Reset SLAM. */
cs423x_slam_enable(dev, 1);
}
static void *
cs423x_init(const device_t *info)
{
cs423x_t *dev = malloc(sizeof(cs423x_t));
memset(dev, 0, sizeof(cs423x_t));
/* Initialize model-specific data. */
dev->type = info->local;
switch (dev->type) {
case CRYSTAL_CS4236B:
case CRYSTAL_CS4237B:
case CRYSTAL_CS4238B:
/* Same WSS codec and EEPROM structure. */
dev->ad1848_type = AD1848_TYPE_CS4236;
dev->pnp_offset = 19;
/* Different Chip Version and ID registers, which shouldn't be reset by ad1848_init */
dev->ad1848.xregs[25] = dev->type;
/* Load EEPROM contents from template. */
memcpy(dev->eeprom_data, cs4236b_eeprom, sizeof(cs4236b_eeprom));
/* Set content size. */
dev->eeprom_data[2] = sizeof(cs4236b_eeprom) >> 8;
dev->eeprom_data[3] = sizeof(cs4236b_eeprom) & 0xff;
/* Set PnP card ID. */
switch (dev->type) {
case CRYSTAL_CS4237B:
dev->eeprom_data[26] = 0x37;
break;
case CRYSTAL_CS4238B:
dev->eeprom_data[26] = 0x38;
break;
}
/* 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);
break;
}
/* Initialize I2C bus for the EEPROM. */
dev->i2c = i2c_gpio_init("nvr_cs423x");
/* Initialize I2C EEPROM if the contents are valid. */
if ((dev->eeprom_data[0] == 0x55) && (dev->eeprom_data[1] == 0xbb))
dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->eeprom_data, sizeof(dev->eeprom_data), 1);
/* Initialize ISAPnP. */
dev->pnp_card = isapnp_add_card(NULL, 0, cs423x_pnp_config_changed, NULL, NULL, NULL, dev);
/* 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);
/* Initialize RAM, registers and WSS codec. */
cs423x_reset(dev);
sound_add_handler(cs423x_get_buffer, dev);
return dev;
}
static void
cs423x_close(void *priv)
{
cs423x_t *dev = (cs423x_t *) priv;
if (dev->eeprom)
i2c_eeprom_close(dev->eeprom);
i2c_gpio_close(dev->i2c);
free(dev);
}
static void
cs423x_speed_changed(void *priv)
{
cs423x_t *dev = (cs423x_t *) priv;
ad1848_speed_changed(&dev->ad1848);
}
const device_t cs4236b_device =
{
"Crystal CS4236B",
DEVICE_ISA | DEVICE_AT,
CRYSTAL_CS4236B,
cs423x_init, cs423x_close, cs423x_reset,
{ NULL },
cs423x_speed_changed,
NULL,
NULL
};
const device_t cs4237b_device =
{
"Crystal CS4237B",
DEVICE_ISA | DEVICE_AT,
CRYSTAL_CS4237B,
cs423x_init, cs423x_close, cs423x_reset,
{ NULL },
cs423x_speed_changed,
NULL,
NULL
};
const device_t cs4238b_device =
{
"Crystal CS4238B",
DEVICE_ISA | DEVICE_AT,
CRYSTAL_CS4238B,
cs423x_init, cs423x_close, cs423x_reset,
{ NULL },
cs423x_speed_changed,
NULL,
NULL
};

View File

@@ -31,6 +31,7 @@
#include <86box/mem.h>
#include <86box/rom.h>
#include <86box/device.h>
#include <86box/gameport.h>
#include <86box/pic.h>
#include <86box/sound.h>
#include <86box/midi.h>
@@ -71,6 +72,9 @@ static const uint16_t sb_mcv_addr[8] = {0x200, 0x210, 0x220, 0x230, 0x240, 0x250
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. */
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) */
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
@@ -87,14 +91,19 @@ static uint8_t sb_16_pnp_rom[] = {
0x47, 0x01, 0x88, 0x03, 0x88, 0x03, 0x01, 0x04, /* I/O 0x388, decodes 16-bit, 1-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_32_pnp_rom[] = {
0x0e, 0x8c, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL009C, dummy checksum (filled in by isapnp_add_card) */
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, 0x41, 0x00, 0xa9, /* logical device CTL0041, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */
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 */
@@ -153,14 +162,19 @@ static uint8_t sb_32_pnp_rom[] = {
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, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, /* CTL009A, dummy checksum (filled in by isapnp_add_card) */
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, 0x41, 0x00, 0xa9, /* logical device CTL0041, supports vendor-specific registers 0x38/0x3A/0x3C/0x3F */
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 */
@@ -223,6 +237,11 @@ static uint8_t sb_awe32_pnp_rom[] = {
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) */
};
@@ -1188,69 +1207,75 @@ sb_pro_mcv_write(int port, uint8_t val, void *p)
static void
sb_16_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv)
{
if (ld != 0)
return;
sb_t *sb = (sb_t *) priv;
uint16_t addr = sb->dsp.sb_addr;
uint8_t val;
io_removehandler(addr, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
io_removehandler(addr + 8, 0x0002, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
io_removehandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL,
sb_ct1745_mixer_write, NULL, NULL, sb);
switch (ld) {
case 0: /* Audio */
io_removehandler(addr, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
io_removehandler(addr + 8, 0x0002, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
io_removehandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL,
sb_ct1745_mixer_write, NULL, NULL, sb);
addr = sb->opl_pnp_addr;
if (addr) {
sb->opl_pnp_addr = 0;
io_removehandler(addr, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
}
addr = sb->opl_pnp_addr;
if (addr) {
sb->opl_pnp_addr = 0;
io_removehandler(addr, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
}
sb_dsp_setaddr(&sb->dsp, 0);
sb_dsp_setirq(&sb->dsp, 0);
sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED);
sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED);
sb_dsp_setaddr(&sb->dsp, 0);
sb_dsp_setirq(&sb->dsp, 0);
sb_dsp_setdma8(&sb->dsp, ISAPNP_DMA_DISABLED);
sb_dsp_setdma16(&sb->dsp, ISAPNP_DMA_DISABLED);
mpu401_change_addr(sb->mpu, 0);
mpu401_change_addr(sb->mpu, 0);
if (config->activate) {
addr = config->io[0].base;
if (addr != ISAPNP_IO_DISABLED) {
io_sethandler(addr, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL,
sb_ct1745_mixer_write, NULL, NULL, sb);
if (config->activate) {
addr = config->io[0].base;
if (addr != ISAPNP_IO_DISABLED) {
io_sethandler(addr, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
io_sethandler(addr + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL,
sb_ct1745_mixer_write, NULL, NULL, sb);
sb_dsp_setaddr(&sb->dsp, addr);
}
sb_dsp_setaddr(&sb->dsp, addr);
}
addr = config->io[1].base;
if (addr != ISAPNP_IO_DISABLED)
mpu401_change_addr(sb->mpu, addr);
addr = config->io[1].base;
if (addr != ISAPNP_IO_DISABLED)
mpu401_change_addr(sb->mpu, addr);
addr = config->io[2].base;
if (addr != ISAPNP_IO_DISABLED) {
sb->opl_pnp_addr = addr;
io_sethandler(addr, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
}
addr = config->io[2].base;
if (addr != ISAPNP_IO_DISABLED) {
sb->opl_pnp_addr = addr;
io_sethandler(addr, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &sb->opl);
}
val = config->irq[0].irq;
if (val != ISAPNP_IRQ_DISABLED)
sb_dsp_setirq(&sb->dsp, val);
val = config->irq[0].irq;
if (val != ISAPNP_IRQ_DISABLED)
sb_dsp_setirq(&sb->dsp, val);
val = config->dma[0].dma;
if (val != ISAPNP_DMA_DISABLED)
sb_dsp_setdma8(&sb->dsp, val);
val = config->dma[0].dma;
if (val != ISAPNP_DMA_DISABLED)
sb_dsp_setdma8(&sb->dsp, val);
val = config->dma[1].dma;
if (val != ISAPNP_DMA_DISABLED)
sb_dsp_setdma16(&sb->dsp, val);
val = config->dma[1].dma;
if (val != ISAPNP_DMA_DISABLED)
sb_dsp_setdma16(&sb->dsp, val);
}
break;
case 1: /* Game */
gameport_remap(sb->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
break;
}
}
@@ -1259,21 +1284,18 @@ static void
sb_awe32_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv)
{
sb_t *sb = (sb_t *) priv;
uint16_t addr;
switch (ld) {
case 0:
case 0: /* Audio */
sb_16_pnp_config_changed(0, config, sb);
break;
case 1:
emu8k_change_addr(&sb->emu8k, 0);
case 1: /* WaveTable */
emu8k_change_addr(&sb->emu8k, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0);
break;
if (config->activate) {
addr = config->io[0].base;
if (addr != ISAPNP_IO_DISABLED)
emu8k_change_addr(&sb->emu8k, addr);
}
case 2: /* Game */
sb_16_pnp_config_changed(1, config, sb);
break;
}
}
@@ -1602,6 +1624,31 @@ sb_pro_mcv_init(const device_t *info)
}
static void *
sb_pro_cs423x_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);
sb_ct1345_mixer_reset(sb);
sb->mixer_enabled = 1;
sound_add_handler(sb_get_buffer_sbpro, sb);
sound_set_cd_audio_filter(sbpro_filter_cd_audio, sb);
sb->mpu = (mpu_t *) malloc(sizeof(mpu_t));
memset(sb->mpu, 0, sizeof(mpu_t));
mpu401_init(sb->mpu, 0, 0, M_UART, 1);
sb_dsp_set_mpu(&sb->dsp, sb->mpu);
return sb;
}
static void *
sb_16_init(const device_t *info)
{
@@ -1676,6 +1723,8 @@ sb_16_pnp_init(const device_t *info)
if (device_get_config_int("receive_input"))
midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp);
sb->gameport = gameport_add(&gameport_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;
@@ -1771,6 +1820,8 @@ sb_awe32_pnp_init(const device_t *info)
if (device_get_config_int("receive_input"))
midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp);
sb->gameport = gameport_add(&gameport_pnp_device);
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
@@ -2483,6 +2534,17 @@ const device_t sb_pro_mcv_device =
NULL
};
const device_t sb_pro_cs423x_device =
{
"Crystal CS423x Sound Blaster Pro compatibility",
DEVICE_ISA | DEVICE_AT,
0,
sb_pro_cs423x_init, sb_close, NULL, { NULL },
sb_speed_changed,
NULL,
NULL
};
const device_t sb_16_device =
{
"Sound Blaster 16",

View File

@@ -34,217 +34,231 @@
#include <86box/snd_opl.h>
/*530, 11, 3 - 530=23*/
/*530, 11, 1 - 530=22*/
/*530, 11, 0 - 530=21*/
/*530, 10, 1 - 530=1a*/
/*530, 9, 1 - 530=12*/
/*530, 7, 1 - 530=0a*/
/*604, 11, 1 - 530=22*/
/*e80, 11, 1 - 530=22*/
/*f40, 11, 1 - 530=22*/
/* 530, 11, 3 - 530=23
* 530, 11, 1 - 530=22
* 530, 11, 0 - 530=21
* 530, 10, 1 - 530=1a
* 530, 9, 1 - 530=12
* 530, 7, 1 - 530=0a
* 604, 11, 1 - 530=22
* e80, 11, 1 - 530=22
* f40, 11, 1 - 530=22
*/
static int wss_dma[4] = {0, 0, 1, 3};
static int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /*W95 only uses 7-9, others may be wrong*/
static const int wss_dma[4] = {0, 0, 1, 3};
static const int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /* W95 only uses 7-9, others may be wrong */
typedef struct wss_t
{
uint8_t config;
ad1848_t ad1848;
opl_t opl;
typedef struct wss_t {
uint8_t config;
int opl_enabled;
uint8_t pos_regs[8];
ad1848_t ad1848;
opl_t opl;
int opl_enabled;
uint8_t pos_regs[8];
} wss_t;
uint8_t wss_read(uint16_t addr, void *p)
{
wss_t *wss = (wss_t *)p;
uint8_t temp;
temp = 4 | (wss->config & 0x40);
return temp;
uint8_t
wss_read(uint16_t addr, void *priv) {
wss_t *wss = (wss_t *) priv;
return 4 | (wss->config & 0x40);
}
void wss_write(uint16_t addr, uint8_t val, void *p)
{
wss_t *wss = (wss_t *)p;
wss->config = val;
ad1848_setdma(&wss->ad1848, wss_dma[val & 3]);
ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]);
void
wss_write(uint16_t addr, uint8_t val, void *priv)
{
wss_t *wss = (wss_t *) priv;
wss->config = val;
ad1848_setdma(&wss->ad1848, wss_dma[val & 3]);
ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]);
}
static void wss_get_buffer(int32_t *buffer, int len, void *p)
static void
wss_get_buffer(int32_t *buffer, int len, void *priv)
{
wss_t *wss = (wss_t *)p;
int c;
wss_t *wss = (wss_t *) priv;
int c;
opl3_update(&wss->opl);
ad1848_update(&wss->ad1848);
for (c = 0; c < len * 2; c++) {
buffer[c] += wss->opl.buffer[c];
buffer[c] += (wss->ad1848.buffer[c] / 2);
}
opl3_update(&wss->opl);
ad1848_update(&wss->ad1848);
for (c = 0; c < len * 2; c++) {
buffer[c] += wss->opl.buffer[c];
buffer[c] += wss->ad1848.buffer[c] / 2;
}
wss->opl.pos = 0;
wss->ad1848.pos = 0;
wss->opl.pos = 0;
wss->ad1848.pos = 0;
}
void *wss_init(const device_t *info)
void *
wss_init(const device_t *info)
{
wss_t *wss = malloc(sizeof(wss_t));
memset(wss, 0, sizeof(wss_t));
wss_t *wss = malloc(sizeof(wss_t));
memset(wss, 0, sizeof(wss_t));
uint16_t addr = device_get_config_hex16("base");
wss->opl_enabled = device_get_config_int("opl");
uint16_t addr = device_get_config_hex16("base");
wss->opl_enabled = device_get_config_int("opl");
if (wss->opl_enabled)
opl3_init(&wss->opl);
ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT);
if (wss->opl_enabled)
opl3_init(&wss->opl);
ad1848_setirq(&wss->ad1848, 7);
ad1848_setdma(&wss->ad1848, 3);
ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT);
if (wss->opl_enabled)
ad1848_setirq(&wss->ad1848, 7);
ad1848_setdma(&wss->ad1848, 3);
if (wss->opl_enabled)
io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl);
io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss);
io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848);
sound_add_handler(wss_get_buffer, wss);
return wss;
}
static uint8_t
ncr_audio_mca_read(int port, void *priv)
{
wss_t *wss = (wss_t *) priv;
return wss->pos_regs[port & 7];
}
static void
ncr_audio_mca_write(int port, uint8_t val, void *priv)
{
wss_t *wss = (wss_t *) priv;
uint16_t ports[4] = {0x530, 0xE80, 0xF40, 0x604};
uint16_t addr;
if (port < 0x102)
return;
wss->opl_enabled = (wss->pos_regs[2] & 0x20) ? 1 : 0;
addr = ports[(wss->pos_regs[2] & 0x18) >> 3];
io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl);
io_removehandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss);
io_removehandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848);
wss->pos_regs[port & 7] = val;
if (wss->pos_regs[2] & 1) {
addr = ports[(wss->pos_regs[2] & 0x18) >> 3];
if (wss->opl_enabled)
io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl);
io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss);
io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848);
sound_add_handler(wss_get_buffer, wss);
return wss;
}
}
static uint8_t ncr_audio_mca_read(int port, void *p)
static uint8_t
ncr_audio_mca_feedb(void *priv)
{
wss_t *wss = (wss_t *)p;
return wss->pos_regs[port & 7];
wss_t *wss = (wss_t *) priv;
return (wss->pos_regs[2] & 1);
}
static void ncr_audio_mca_write(int port, uint8_t val, void *p)
void *
ncr_audio_init(const device_t *info)
{
wss_t *wss = (wss_t *)p;
uint16_t ports[4] = {0x530, 0xE80, 0xF40, 0x604};
uint16_t addr;
wss_t *wss = malloc(sizeof(wss_t));
memset(wss, 0, sizeof(wss_t));
if (port < 0x102)
return;
opl3_init(&wss->opl);
ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT);
wss->opl_enabled = (wss->pos_regs[2] & 0x20) ? 1 : 0;
addr = ports[(wss->pos_regs[2] & 0x18) >> 3];
io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl);
io_removehandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss);
io_removehandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848);
ad1848_setirq(&wss->ad1848, 7);
ad1848_setdma(&wss->ad1848, 3);
wss->pos_regs[port & 7] = val;
mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, NULL, wss);
wss->pos_regs[0] = 0x16;
wss->pos_regs[1] = 0x51;
if (wss->pos_regs[2] & 1) {
addr = ports[(wss->pos_regs[2] & 0x18) >> 3];
sound_add_handler(wss_get_buffer, wss);
if (wss->opl_enabled)
io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl);
io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss);
io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848);
}
return wss;
}
static uint8_t ncr_audio_mca_feedb(void *p)
{
wss_t *wss = (wss_t *)p;
return (wss->pos_regs[2] & 1);
void
wss_close(void *priv)
{
wss_t *wss = (wss_t *) priv;
free(wss);
}
void *ncr_audio_init(const device_t *info)
void
wss_speed_changed(void *priv)
{
wss_t *wss = malloc(sizeof(wss_t));
memset(wss, 0, sizeof(wss_t));
opl3_init(&wss->opl);
ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT);
ad1848_setirq(&wss->ad1848, 7);
ad1848_setdma(&wss->ad1848, 3);
mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, NULL, wss);
wss->pos_regs[0] = 0x16;
wss->pos_regs[1] = 0x51;
sound_add_handler(wss_get_buffer, wss);
return wss;
wss_t *wss = (wss_t *) priv;
ad1848_speed_changed(&wss->ad1848);
}
void wss_close(void *p)
{
wss_t *wss = (wss_t *)p;
free(wss);
}
void wss_speed_changed(void *p)
{
wss_t *wss = (wss_t *)p;
ad1848_speed_changed(&wss->ad1848);
}
static const device_config_t wss_config[] =
{
{
"base", "Address", CONFIG_HEX16, "", 0x530, "", { 0 },
{
{
"0x530", 0x530
},
{
"0x604", 0x604
},
{
"0xe80", 0xe80
},
{
"0xf40", 0xf40
},
{
""
}
}
},
static const device_config_t wss_config[] = {
{
"base", "Address", CONFIG_HEX16, "", 0x530, "", { 0 },
{
"opl", "Enable OPL", CONFIG_BINARY, "", 1
},
{
"", "", -1
}
{
"0x530", 0x530
},
{
"0x604", 0x604
},
{
"0xe80", 0xe80
},
{
"0xf40", 0xf40
},
{
""
}
}
},
{
"opl", "Enable OPL", CONFIG_BINARY, "", 1
},
{
"", "", -1
}
};
const device_t wss_device =
{
"Windows Sound System",
DEVICE_ISA | DEVICE_AT, 0,
wss_init, wss_close, NULL,
{ NULL },
wss_speed_changed,
NULL,
wss_config
"Windows Sound System",
DEVICE_ISA | DEVICE_AT, 0,
wss_init, wss_close, NULL,
{ NULL },
wss_speed_changed,
NULL,
wss_config
};
const device_t ncr_business_audio_device =
{
"NCR Business Audio",
DEVICE_MCA, 0,
ncr_audio_init, wss_close, NULL,
{ NULL },
wss_speed_changed,
NULL,
NULL
"NCR Business Audio",
DEVICE_MCA, 0,
ncr_audio_init, wss_close, NULL,
{ NULL },
wss_speed_changed,
NULL,
NULL
};

View File

@@ -88,6 +88,7 @@ static const SOUND_CARD sound_cards[] =
{ "adlibgold", &adgold_device },
{ "azt2316a", &azt2316a_device },
{ "azt1605", &azt1605_device },
{ "cs4236b", &cs4236b_device },
{ "sb", &sb_1_device },
{ "sb1.5", &sb_15_device },
{ "sb2.0", &sb_2_device },

View File

@@ -634,7 +634,6 @@ MCHOBJ := machine.o machine_table.o \
m_at_286_386sx.o m_at_386dx_486.o \
m_at_socket4_5.o m_at_socket7.o m_at_sockets7.o \
m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \
m_at_ebga368.o \
m_at_misc.o
DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \
@@ -724,7 +723,7 @@ SNDOBJ := sound.o \
snd_pssj.o \
snd_lpt_dac.o snd_lpt_dss.o \
snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \
snd_azt2316a.o \
snd_azt2316a.o snd_cs423x.o \
snd_cms.o \
snd_gus.o \
snd_sb.o snd_sb_dsp.o \