Merge pull request #1470 from richardg867/feature/cs423x
Game port overhaul, Crystal CS423xB and other changes
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 *);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -122,6 +122,7 @@ typedef struct sb_t
|
||||
};
|
||||
mpu_t *mpu;
|
||||
emu8k_t emu8k;
|
||||
void *gameport;
|
||||
|
||||
int pos;
|
||||
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
829
src/sound/snd_cs423x.c
Normal 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
|
||||
};
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 \
|
||||
|
||||
Reference in New Issue
Block a user