ESS AudioDrive: Fix some mixer register and DSP command readouts to match the probing of real cards, also fixes Windows 3.1 ES688 drivers.

This commit is contained in:
OBattler
2024-12-07 01:17:36 +01:00
parent cc8cfb7b3f
commit 025e3b3088
2 changed files with 79 additions and 44 deletions

View File

@@ -1452,9 +1452,6 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
if (!(addr & 1)) {
mixer->index = val;
mixer->regs[0x01] = val;
if (val == 0x40) {
mixer->ess_id_str_pos = 0;
}
} else {
if (mixer->index == 0) {
/* Reset */
@@ -1473,6 +1470,8 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
mixer->regs[0x3c] = 0x05;
mixer->regs[0x3e] = 0x00;
mixer->regs[0x64] = 0x08;
sb_dsp_set_stereo(&ess->dsp, mixer->regs[0x0e] & 2);
} else {
mixer->regs[mixer->index] = val;
@@ -1525,6 +1524,7 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
break;
case 0x1C:
mixer->regs[mixer->index] = val & 0x2f;
if ((mixer->regs[0x1C] & 0x07) == 0x07) {
mixer->input_selector = INPUT_MIXER_L | INPUT_MIXER_R;
} else if ((mixer->regs[0x1C] & 0x07) == 0x06) {
@@ -1556,12 +1556,12 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
break;
case 0x64:
mixer->regs[mixer->index] = (mixer->regs[mixer->index] & 0xf7) | 0x20;
// mixer->regs[mixer->index] &= ~0x8;
if (ess->dsp.sb_subtype > SB_SUBTYPE_ESS_ES1688)
mixer->regs[mixer->index] = (mixer->regs[mixer->index] & 0xf7) | 0x20;
break;
case 0x40:
{
if (ess->dsp.sb_subtype >= SB_SUBTYPE_ESS_ES1688) {
uint16_t mpu401_base_addr = 0x300 | ((mixer->regs[0x40] << 1) & 0x30);
sb_log("mpu401_base_addr = %04X\n", mpu401_base_addr);
@@ -1572,7 +1572,7 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
gameport_remap(ess->gameport, !(mixer->regs[0x40] & 0x2) ? 0x00 : 0x200);
if (ess->dsp.sb_subtype != SB_SUBTYPE_ESS_ES1688) {
if (ess->dsp.sb_subtype > SB_SUBTYPE_ESS_ES1688) {
/* Not on ES1688. */
io_removehandler(0x0388, 0x0004,
ess->opl.read, NULL, NULL,
@@ -1585,6 +1585,7 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
ess->opl.priv);
}
}
if (ess->mpu != NULL) switch ((mixer->regs[0x40] >> 5) & 0x7) {
default:
break;
@@ -1627,11 +1628,12 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
ess_fm_midi_read, NULL, NULL,
ess_fm_midi_write, NULL, NULL,
ess);
break;
}
break;
default:
sb_log("ess: Unknown mixer register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
sb_log("ess: Unknown mixer register WRITE: %02X\t%02X\n",
mixer->index, mixer->regs[mixer->index]);
break;
}
}
@@ -1667,6 +1669,7 @@ ess_mixer_read(uint16_t addr, void *priv)
case 0x0c:
case 0x0e:
case 0x14:
case 0x1a:
case 0x02:
case 0x06:
case 0x30:
@@ -1685,28 +1688,56 @@ ess_mixer_read(uint16_t addr, void *priv)
ret = mixer->regs[mixer->index] | 0x11;
break;
case 0x40:
if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688)
ret = mixer->regs[mixer->index];
else
ret = 0x0a;
/* Bit 1 always set, bits 7-6 always clear on both the real ES688 and ES1688. */
case 0x1c:
ret = mixer->regs[mixer->index] | 0x10;
break;
case 0x48:
ret = mixer->regs[mixer->index];
break;
/*
Real ES688: Always 0x00;
Real ES1688: Bit 2 always clear.
*/
case 0x40:
if (ess->dsp.sb_subtype > SB_SUBTYPE_ESS_ES1688)
ret = mixer->regs[mixer->index];
else if (ess->dsp.sb_subtype >= SB_SUBTYPE_ESS_ES1688)
ret = mixer->regs[mixer->index] & 0xfb;
else
ret = 0x00;
break;
/* Return 0x00 so it has bit 3 clear, so NT 5.x drivers don't misdetect it as ES1788. */
/*
Real ES688: Always 0x00;
Real ES1688: All bits writable.
*/
case 0x48:
if (ess->dsp.sb_subtype >= SB_SUBTYPE_ESS_ES1688)
ret = mixer->regs[mixer->index];
else
ret = 0x00;
break;
/*
Return 0x00 so it has bit 3 clear, so NT 5.x drivers don't misdetect it as ES1788.
Bit 3 set and writable: ESSCFG detects the card as ES1788 if register 70h is read-only,
otherwise, as ES1887.
Bit 3 set and read-only: ESSCFG detects the card as ES1788 if register 70h is read-only,
otherwise, as ES1888.
Real ES688 and ES1688: Always 0x00.
*/
case 0x64:
ret = (mixer->regs[mixer->index] & 0xf7) | 0x20;
if (ess->dsp.sb_subtype > SB_SUBTYPE_ESS_ES1688)
ret = (mixer->regs[mixer->index] & 0xf7) | 0x20;
else
ret = 0x00;
break;
default:
sb_log("ess: Unknown mixer register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
sb_log("ess: Unknown mixer register READ: %02X\t%02X\n", mixer->index, mixer->regs[miwinxer->index]);
break;
}
sb_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret);
sb_log("[%04X:%08X] [R] %04X = %02X (%02X)\n", CS, cpu_state.pc, addr, ret, mixer->index);
return ret;
}
@@ -2268,9 +2299,6 @@ ess_x688_pnp_config_changed(UNUSED(const uint8_t ld), isapnp_device_config_t *co
ess_base_write, NULL, NULL,
ess);
ess->mixer_ess.ess_id_str[2] = 0x00;
ess->mixer_ess.ess_id_str[3] = 0x00;
addr = ess->opl_pnp_addr;
if (addr) {
ess->opl_pnp_addr = 0;
@@ -2337,9 +2365,6 @@ ess_x688_pnp_config_changed(UNUSED(const uint8_t ld), isapnp_device_config_t *co
ess_base_read, NULL, NULL,
ess_base_write, NULL, NULL,
ess);
ess->mixer_ess.ess_id_str[2] = (addr >> 8) & 0xff;
ess->mixer_ess.ess_id_str[3] = addr & 0xff;
}
addr = config->io[1].base;
@@ -3748,11 +3773,6 @@ ess_x688_init(UNUSED(const device_t *info))
midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &ess->dsp);
if (info->local) {
ess->mixer_ess.ess_id_str[0] = 0x16;
ess->mixer_ess.ess_id_str[1] = 0x88;
ess->mixer_ess.ess_id_str[2] = (addr >> 8) & 0xff;
ess->mixer_ess.ess_id_str[3] = addr & 0xff;
ess->mpu = (mpu_t *) calloc(1, sizeof(mpu_t));
/* NOTE: The MPU is initialized disabled and with no IRQ assigned.
* It will be later initialized by the guest OS's drivers. */
@@ -3818,12 +3838,6 @@ ess_x688_pnp_init(UNUSED(const device_t *info))
if (device_get_config_int("receive_input"))
midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &ess->dsp);
/* Not on ES688. */
ess->mixer_ess.ess_id_str[0] = 0x16;
ess->mixer_ess.ess_id_str[1] = 0x88;
ess->mixer_ess.ess_id_str[2] = 0x00;
ess->mixer_ess.ess_id_str[3] = 0x00;
ess->mpu = (mpu_t *) calloc(1, sizeof(mpu_t));
/* NOTE: The MPU is initialized disabled and with no IRQ assigned.
* It will be later initialized by the guest OS's drivers. */

View File

@@ -1687,6 +1687,10 @@ sb_exec_command(sb_dsp_t *dsp)
break;
case 0xE1: /* Get DSP version */
if (IS_ESS(dsp)) {
/*
0x03 0x01 (Sound Blaster Pro compatibility) confirmed by both the
ES1888 datasheet and the probing of the real ES688 and ES1688 cards.
*/
sb_add_data(dsp, 0x3);
sb_add_data(dsp, 0x1);
break;
@@ -1722,9 +1726,12 @@ sb_exec_command(sb_dsp_t *dsp)
while (sb16_copyright[c])
sb_add_data(dsp, sb16_copyright[c++]);
sb_add_data(dsp, 0);
} else if (IS_ESS(dsp)) {
sb_add_data(dsp, 0);
}
} /* else if (IS_ESS(dsp))
sb_add_data(dsp, 0); */
/*
TODO: What ESS card returns 0x00 here? Probing of the real ES688 and ES1688 cards
revealed that they in fact return nothing on this command.
*/
break;
case 0xE4: /* Write test register */
dsp->sb_test = dsp->sb_data[0];
@@ -1736,12 +1743,26 @@ sb_exec_command(sb_dsp_t *dsp)
break;
case SB_SUBTYPE_ESS_ES688:
sb_add_data(dsp, 0x68);
sb_add_data(dsp, 0x80 | 0x04);
/*
80h: ESSCFG fails to detect the AudioDrive;
81h-83h: ES??88, Windows 3.1 driver expects MPU-401 and gives a legacy mixer error;
84h: ES688, Windows 3.1 driver expects MPU-401, returned by DOSBox-X;
85h-87h: ES688, Windows 3.1 driver does not expect MPU-401:
85h: Returned by MSDOS622's real ESS688,
86h: Returned by Dizzy's real ES688.
We return 86h if MPU is absent, 84h otherwise, who knows what the actual
PnP ES688 returns here.
*/
sb_add_data(dsp, 0x80 | ((dsp->mpu != NULL) ? 0x04 : 0x06));
break;
case SB_SUBTYPE_ESS_ES1688:
// Determined via Windows driver debugging.
sb_add_data(dsp, 0x68);
sb_add_data(dsp, 0x80 | 0x09);
/*
89h: ES1688, returned by DOSBox-X, determined via Windows driver
debugging;
8Bh: ES1688, returned by both MSDOS622's and Dizzy's real ES1688's.
*/
sb_add_data(dsp, 0x80 | 0x0b);
break;
}
}