Add CMI8x38 legacy function remapping

This commit is contained in:
RichardG867
2022-02-28 22:31:44 -03:00
parent 6f6bf999fa
commit 60e316cc01

View File

@@ -54,7 +54,7 @@ typedef struct {
} cmi8x38_dma_t; } cmi8x38_dma_t;
typedef struct _cmi8x38_ { typedef struct _cmi8x38_ {
uint16_t io_base; uint16_t io_base, sb_base, opl_base, mpu_base;
uint8_t type, pci_regs[256], io_regs[256], mixer_ext_regs[16]; uint8_t type, pci_regs[256], io_regs[256], mixer_ext_regs[16];
int slot; int slot;
@@ -85,6 +85,7 @@ cmi8x38_log(const char *fmt, ...)
#endif #endif
static const double freqs[] = {5512.0, 11025.0, 22050.0, 44100.0, 8000.0, 16000.0, 32000.0, 48000.0}; static const double freqs[] = {5512.0, 11025.0, 22050.0, 44100.0, 8000.0, 16000.0, 32000.0, 48000.0};
static const uint16_t opl_ports_cmi8738[] = {0x388, 0x3c8, 0x3e0, 0x3e8};
static void cmi8x38_dma_process(void *priv); static void cmi8x38_dma_process(void *priv);
@@ -106,6 +107,90 @@ cmi8x38_update_irqs(cmi8x38_t *dev)
} }
static void
cmi8x38_remap_sb(cmi8x38_t *dev)
{
if (dev->sb_base) {
io_removehandler(dev->sb_base, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &dev->sb->opl);
io_removehandler(dev->sb_base + 8, 0x0002, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &dev->sb->opl);
io_removehandler(dev->sb_base + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL,
sb_ct1745_mixer_write, NULL, NULL, dev->sb);
sb_dsp_setaddr(&dev->sb->dsp, 0);
}
if (dev->io_regs[0x04] & 0x08) {
dev->sb_base = 0x220;
if (dev->type == CMEDIA_CMI8338)
dev->sb_base += (dev->io_regs[0x17] & 0x80) >> 2;
else
dev->sb_base += (dev->io_regs[0x17] & 0x0c) << 3;
} else {
dev->sb_base = 0;
}
cmi8x38_log("CMI8x38: remap_sb(%04X)\n", dev->sb_base);
if (dev->sb_base) {
io_sethandler(dev->sb_base, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &dev->sb->opl);
io_sethandler(dev->sb_base + 8, 0x0002, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &dev->sb->opl);
io_sethandler(dev->sb_base + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL,
sb_ct1745_mixer_write, NULL, NULL, dev->sb);
sb_dsp_setaddr(&dev->sb->dsp, dev->sb_base);
}
}
static void
cmi8x38_remap_opl(cmi8x38_t *dev)
{
if (dev->opl_base) {
io_removehandler(dev->opl_base, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &dev->sb->opl);
}
if (dev->io_regs[0x04] & 0x08) {
if (dev->type == CMEDIA_CMI8338)
dev->opl_base = 0x388;
else
dev->opl_base = opl_ports_cmi8738[dev->io_regs[0x17] & 0x03];
} else {
dev->opl_base = 0;
}
cmi8x38_log("CMI8x38: remap_opl(%04X)\n", dev->opl_base);
if (dev->opl_base) {
io_sethandler(dev->opl_base, 0x0004, opl3_read, NULL, NULL,
opl3_write, NULL, NULL, &dev->sb->opl);
}
}
static void
cmi8x38_remap_mpu(cmi8x38_t *dev)
{
if (dev->mpu_base)
mpu401_change_addr(dev->sb->mpu, 0);
if (dev->io_regs[0x04] & 0x04) {
if (dev->type == CMEDIA_CMI8338)
dev->mpu_base = 0x300 + ((dev->io_regs[0x17] & 0x60) >> 1);
else
dev->mpu_base = 0x330 - ((dev->io_regs[0x17] & 0x60) >> 1);
} else {
dev->mpu_base = 0;
}
cmi8x38_log("CMI8x38: remap_mpu(%04X)\n", dev->mpu_base);
if (dev->mpu_base)
mpu401_change_addr(dev->sb->mpu, dev->mpu_base);
}
static void static void
cmi8x38_start_playback(cmi8x38_t *dev, uint8_t val) cmi8x38_start_playback(cmi8x38_t *dev, uint8_t val)
{ {
@@ -248,6 +333,12 @@ cmi8x38_write(uint16_t addr, uint8_t val, void *priv)
case 0x04: case 0x04:
/* Enable or disable the game port. */ /* Enable or disable the game port. */
gameport_remap(dev->gameport, (val & 0x02) ? 0x200 : 0); gameport_remap(dev->gameport, (val & 0x02) ? 0x200 : 0);
/* Enable or disable the legacy devices. */
dev->io_regs[addr] = val;
cmi8x38_remap_sb(dev);
cmi8x38_remap_opl(dev);
cmi8x38_remap_mpu(dev);
break; break;
case 0x05: case 0x05:
@@ -310,6 +401,12 @@ cmi8x38_write(uint16_t addr, uint8_t val, void *priv)
else if ((dev->io_regs[0x17] & 0x10) && !(val & 0x10)) else if ((dev->io_regs[0x17] & 0x10) && !(val & 0x10))
pci_clear_irq(dev->slot, PCI_INTA); pci_clear_irq(dev->slot, PCI_INTA);
} }
/* Remap the legacy devices. */
dev->io_regs[addr] = val;
cmi8x38_remap_sb(dev);
cmi8x38_remap_opl(dev);
cmi8x38_remap_mpu(dev);
break; break;
case 0x18: case 0x18:
@@ -439,15 +536,12 @@ cmi8x38_write(uint16_t addr, uint8_t val, void *priv)
static void static void
cmi8x38_remap(cmi8x38_t *dev, uint8_t io_msb, uint8_t enable) cmi8x38_remap(cmi8x38_t *dev)
{ {
if (dev->io_base) if (dev->io_base)
io_removehandler(dev->io_base, 256, cmi8x38_read, NULL, NULL, cmi8x38_write, NULL, NULL, dev); io_removehandler(dev->io_base, 256, cmi8x38_read, NULL, NULL, cmi8x38_write, NULL, NULL, dev);
if (enable & 0x01) dev->io_base = (dev->pci_regs[0x04] & 0x01) ? (dev->pci_regs[0x11] << 8) : 0;
dev->io_base = io_msb << 8;
else
dev->io_base = 0;
cmi8x38_log("CMI8x38: remap(%04X)\n", dev->io_base); cmi8x38_log("CMI8x38: remap(%04X)\n", dev->io_base);
if (dev->io_base) if (dev->io_base)
@@ -483,7 +577,10 @@ cmi8x38_pci_write(int func, int addr, uint8_t val, void *priv)
switch (addr) { switch (addr) {
case 0x04: case 0x04:
val &= 0x05; val &= 0x05;
cmi8x38_remap(dev, dev->pci_regs[0x11], val);
/* Enable or disable the I/O BAR. */
dev->pci_regs[addr] = val;
cmi8x38_remap(dev);
break; break;
case 0x05: case 0x05:
@@ -491,7 +588,9 @@ cmi8x38_pci_write(int func, int addr, uint8_t val, void *priv)
break; break;
case 0x11: case 0x11:
cmi8x38_remap(dev, val, dev->pci_regs[0x04]); /* Remap the I/O BAR. */
dev->pci_regs[addr] = val;
cmi8x38_remap(dev);
break; break;
case 0x2c: case 0x2d: case 0x2e: case 0x2f: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
@@ -694,6 +793,8 @@ cmi8x38_speed_changed(void *priv)
cmi8x38_t *dev = (cmi8x38_t *) priv; cmi8x38_t *dev = (cmi8x38_t *) priv;
double freq; double freq;
uint8_t dsr = dev->io_regs[0x09], freqreg = dev->io_regs[0x05] >> 2; uint8_t dsr = dev->io_regs[0x09], freqreg = dev->io_regs[0x05] >> 2;
char buf[256];
sprintf(buf, "%02X-%02X", dsr, freqreg);
/* CMI8338 claims the frequency controls are for DAC (playback) and ADC (recording) /* CMI8338 claims the frequency controls are for DAC (playback) and ADC (recording)
respectively, while CMI8738 claims they're for channel 0 and channel 1. The Linux respectively, while CMI8738 claims they're for channel 0 and channel 1. The Linux
@@ -708,12 +809,14 @@ cmi8x38_speed_changed(void *priv)
case 0x03: freq = 128000.0; break; case 0x03: freq = 128000.0; break;
default: freq = freqs[freqreg & 0x07]; break; default: freq = freqs[freqreg & 0x07]; break;
} }
sprintf(&buf[strlen(buf)], " %d:%X-%X-%.0f", i, dsr & 0x03, freqreg & 0x07, freq);
dsr >>= 2; dsr >>= 2;
freqreg >>= 3; freqreg >>= 3;
/* Set period. */ /* Set period. */
dev->dma[i].timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / freq)); dev->dma[i].timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / freq));
} }
ui_sb_bugui(buf);
} }