From e42f1359d807b8970b98beb3f847adcd3869e0a7 Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Sun, 4 Jan 2026 21:28:12 -0600 Subject: [PATCH] Implement the Aztech AZTPR16 audio controller (and other Aztech improvements) (#6673) * Aztech: Clean up unused code and outdated comments, add a standard 86Box header comment and fix a warning in the logging code * Aztech: Implement gameport enable/disable for AZT1605 and AZT2316A * Aztech: Implement SBPro mixer restore from EEPROM for AZT2316A * Implement the Aztech Sound Galaxy Pro 16 (AZTPR16) sound card * AZTPR16: Right shift master volume by 1 during mixer update, fixes quiet audio in DOS WSS sound test * AZTPR16: Set the Panasonic CD-ROM bit in the config word, fixes CR56X.SYS on Packard Bell 141233 boot disk --- src/include/86box/snd_azt2316a.h | 2 + src/include/86box/snd_sb_dsp.h | 9 +- src/include/86box/sound.h | 1 + src/sound/snd_azt2316a.c | 808 +++++++++++++++++++++++++++---- src/sound/snd_sb.c | 101 ++++ src/sound/snd_sb_dsp.c | 17 +- src/sound/sound.c | 1 + 7 files changed, 834 insertions(+), 105 deletions(-) diff --git a/src/include/86box/snd_azt2316a.h b/src/include/86box/snd_azt2316a.h index 8aae3f1ff..266193e55 100644 --- a/src/include/86box/snd_azt2316a.h +++ b/src/include/86box/snd_azt2316a.h @@ -2,5 +2,7 @@ #define SOUND_AZT2316A_H extern void azt2316a_enable_wss(uint8_t enable, void *priv); +extern void aztpr16_update_mixer(void *priv); +extern void aztpr16_wss_mode(uint8_t mode, void *priv); #endif /*SOUND_AZT2316A*/ diff --git a/src/include/86box/snd_sb_dsp.h b/src/include/86box/snd_sb_dsp.h index 0bc719d98..200912c42 100644 --- a/src/include/86box/snd_sb_dsp.h +++ b/src/include/86box/snd_sb_dsp.h @@ -8,16 +8,17 @@ #define SB_SUBTYPE_CLONE_AZT2316A_0X11 1 /* Aztech Sound Galaxy Pro 16 AB, DSP 3.1 - SBPRO2 clone */ #define SB_SUBTYPE_CLONE_AZT1605_0X0C 2 /* Aztech Sound Galaxy Nova 16 Extra / Packard Bell Forte 16, DSP 2.1 - SBPRO2 clone */ -#define SB_SUBTYPE_ESS_ES688 3 /* ESS Technology ES688 */ -#define SB_SUBTYPE_ESS_ES1688 4 /* ESS Technology ES1688 */ +#define SB_SUBTYPE_CLONE_AZTPR16_0X09 3 /* Aztech Sound Galaxy Pro 16 Extra */ +#define SB_SUBTYPE_ESS_ES688 4 /* ESS Technology ES688 */ +#define SB_SUBTYPE_ESS_ES1688 5 /* ESS Technology ES1688 */ /* ESS-related */ #define IS_ESS(dsp) ((dsp)->sb_subtype >= SB_SUBTYPE_ESS_ES688) /* Check for future ESS cards here */ #define IS_NOT_ESS(dsp) ((dsp)->sb_subtype < SB_SUBTYPE_ESS_ES688) /* Check for future ESS cards here */ /* aztech-related */ -#define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) /* check for future AZT cards here */ -#define AZTECH_EEPROM_SIZE 16 +#define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09) /* check for future AZT cards here */ +#define AZTECH_EEPROM_SIZE 36 typedef struct sb_dsp_t { int sb_type; diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index f3cbaeea1..9dec03231 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -134,6 +134,7 @@ extern const device_t azt2316a_device; extern const device_t acermagic_s20_device; extern const device_t mirosound_pcm10_device; extern const device_t azt1605_device; +extern const device_t aztpr16_device; /* C-Media CMI8x38 */ extern const device_t cmi8338_device; diff --git a/src/sound/snd_azt2316a.c b/src/sound/snd_azt2316a.c index 47cf0296b..08fca0f87 100644 --- a/src/sound/snd_azt2316a.c +++ b/src/sound/snd_azt2316a.c @@ -1,4 +1,25 @@ /* + * 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. + * + * Aztech Sound Galaxy series audio controller emulation. + * + * Authors: Cacodemon345 + * Eluan Costa Miranda + * win2kgamer + * + * Copyright 2022 Cacodemon345. + * Copyright 2020 Eluan Costa Miranda. + * Copyright 2025-2026 win2kgamer + */ + +/* + * Original header and notes: + * * TYPE 0x11: (Washington) * Aztech MMPRO16AB, * Aztech Sound Galaxy Pro 16 AB @@ -66,7 +87,7 @@ * to call the original functions, except for initialization. * * TODO/Notes: - * -Some stuff still not understood on I/O addresses 0x624 and 0x530-0x533. + * -Some stuff still not understood on I/O address 0x624. * -Is the CS42xx dither mode used anywhere? Implement. * -What are the voice commands mode in Win95 mixer again? * -Configuration options not present on Aztech's CONFIG.EXE have been commented @@ -100,14 +121,6 @@ * this behaves like a card with a regular interface disabled by jumper and * the configuration just adds/removes the drivers (which will see other IDE * interfaces present) from the boot process. - * -Continue reverse engineering to see if the AZT1605 shares the SB DMA with - * WSS or if it is set separately by the TSR loaded on boot. Currently it is - * only set by PCem config and then saved to EEPROM (which would make it fixed - * if loading from EEPROM too). - * -Related to the previous note, part of the SBPROV2 emulation on the CLINTON - * family appears to be implemented with a TSR. It's better to remove the TSR - * for now. I need to investigate this. Mixer is also weird under DOS (and - * wants to save to EEPROM? I don't think the WASHINGTON does this). * -Search for TODO in this file. :-) * * Misc things I use to test for regressions: Windows sounds, Descent under @@ -147,6 +160,7 @@ #include <86box/nvr.h> #include <86box/pic.h> #include <86box/sound.h> +#include <86box/gameport.h> #include <86box/snd_ad1848.h> #include <86box/snd_azt2316a.h> #include <86box/snd_sb.h> @@ -159,7 +173,7 @@ int aztech_do_log = ENABLE_AZTECH_LOG; static void aztech_log(void *priv, const char *fmt, ...) { - if (aztech_log) { + if (aztech_do_log) { va_list ap; va_start(ap, fmt); log_out(priv, fmt, ap); @@ -187,6 +201,8 @@ static int azt2316a_wss_irq[8] = { 5, 7, 9, 10, 11, 12, 14, 15 }; /* W95 only us static uint16_t azt2316a_wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40}; #endif +static double aztpr16_vols_5bits[32]; + typedef struct azt2316a_t { int type; @@ -200,8 +216,11 @@ typedef struct azt2316a_t { int cur_wss_enabled; int cur_wss_irq; int cur_wss_dma; + int cur_wss_dma16; /* AZTPR16 16-bit DMA */ int cur_mpu401_irq; int cur_mpu401_enabled; + int gameport_enabled; + void *gameport; uint32_t config_word; uint32_t config_word_unlocked; @@ -216,6 +235,24 @@ typedef struct azt2316a_t { void * log; /* New logging system */ } azt2316a_t; +void +aztpr16_update_mixer(void *priv) +{ + azt2316a_t *azt2316a = (azt2316a_t *) priv; + + aztech_log(azt2316a->log, "Aztech AZTPR16 Mixer update\n"); + + azt2316a->ad1848.regs[2] = ((~azt2316a->sb->mixer_sbpro.regs[0xa0]) & 0x1f); /* CD L */ + azt2316a->ad1848.cd_vol_l = aztpr16_vols_5bits[azt2316a->ad1848.regs[2] & 0x1f]; + azt2316a->ad1848.regs[3] = ((~azt2316a->sb->mixer_sbpro.regs[0xa2]) & 0x1f); /* CD R */ + azt2316a->ad1848.cd_vol_r = aztpr16_vols_5bits[azt2316a->ad1848.regs[3] & 0x1f]; + azt2316a->ad1848.regs[4] = ((~azt2316a->sb->mixer_sbpro.regs[0x8c]) & 0x1f); /* FM L */ + azt2316a->ad1848.regs[5] = ((~azt2316a->sb->mixer_sbpro.regs[0x8e]) & 0x1f); /* FM R */ + azt2316a->ad1848.regs[6] = (((~azt2316a->sb->mixer_sbpro.regs[0x84]) & 0x3f) >> 1); /* Master L */ + azt2316a->ad1848.regs[7] = (((~azt2316a->sb->mixer_sbpro.regs[0x86]) & 0x3f) >> 1); /* Master R */ + +} + static void azt1605_filter_opl(void *priv, double *out_l, double *out_r) { @@ -230,9 +267,6 @@ azt2316a_wss_read(uint16_t addr, void *priv) const azt2316a_t *azt2316a = (azt2316a_t *) priv; uint8_t temp; - /* TODO: when windows is initializing, writing 0x48, 0x58 and 0x60 to - 0x530 makes reading from 0x533 return 0x44, but writing 0x50 - makes this return 0x04. Why? */ if (addr & 1) temp = 4 | (azt2316a->wss_config & 0x40); else @@ -274,6 +308,190 @@ azt2316a_wss_write(uint16_t addr, uint8_t val, void *priv) } /* generate a config word based on current settings */ +static void +aztpr16_create_config_word(void *priv) +{ + azt2316a_t *azt2316a = (azt2316a_t *) priv; + uint32_t temp = 0; + + /* not implemented / hardcoded */ + uint8_t cd_type = 1; + uint8_t cd_irq = 0; + + switch (azt2316a->cur_addr) { + case 0x220: + // do nothing + break; + case 0x240: + temp += 1 << 0; + break; + case 0x260: + temp += 2 << 0; + break; + case 0x280: + temp += 3 << 0; + break; + default: + break; + } + + switch (azt2316a->cur_irq) { + case 2: + temp += 1 << 8; + break; + case 5: + temp += 1 << 9; + break; + case 7: + temp += 1 << 10; + break; + case 10: + temp += 1 << 11; + break; + + default: + break; + } + + switch (azt2316a->cur_wss_addr) { + case 0x530: + // do nothing + break; + case 0x604: + temp += 1 << 16; + break; + case 0xE80: + temp += 2 << 16; + break; + case 0xF40: + temp += 3 << 16; + break; + + default: + break; + } + + if (azt2316a->cur_wss_enabled) + temp += 1 << 18; + + if (azt2316a->gameport_enabled) + temp += 1 << 4; + + switch (azt2316a->cur_mpu401_addr) { + case 0x300: + // do nothing + break; + case 0x330: + temp += 1 << 2; + break; + + default: + break; + } + + if (azt2316a->cur_mpu401_enabled) + temp += 1 << 3; + + switch (cd_type) { + case 0: // disabled + //do nothing + temp += 0 << 5; + break; + case 1: // panasonic + temp += 1 << 5; + break; + case 2: // mitsumi/sony/aztech + temp += 2 << 5; + break; + case 3: // all enabled + temp += 3 << 5; + break; + case 4: // unused + temp += 4 << 5; + break; + case 5: // unused + temp += 5 << 5; + break; + case 6: // unused + temp += 6 << 5; + break; + case 7: // unused + temp += 7 << 5; + break; + + default: + break; + } + + switch (azt2316a->cur_dma) { + case 0: + temp += 1 << 24; + break; + case 1: + temp += 1 << 25; + break; + case 3: + temp += 1 << 26; + break; + default: + break; + } + + switch (azt2316a->cur_wss_dma16) { + case 5: + temp += 1 << 27; + break; + case 6: + temp += 1 << 28; + break; + case 7: + temp += 1 << 29; + break; + default: + break; + } + + switch (azt2316a->cur_mpu401_irq) { + case 2: + temp += 1 << 12; + break; + case 5: + temp += 1 << 13; + break; + case 7: + temp += 1 << 14; + break; + case 10: + temp += 1 << 15; + break; + + default: + break; + } + + switch (cd_irq) { + case 0: // disabled + // do nothing + break; + case 11: + temp += 1 << 20; + break; + case 12: + temp += 1 << 21; + break; + case 15: + temp += 1 << 22; + break; + + default: + break; + } + + azt2316a->config_word = temp; + aztech_log(azt2316a->log, "Aztech PR16 Config Word Create: %08X\n", temp); +} + + static void azt1605_create_config_word(void *priv) { @@ -281,7 +499,6 @@ azt1605_create_config_word(void *priv) uint32_t temp = 0; /* not implemented / hardcoded */ - uint8_t game_enable = 1; uint8_t cd_type = 0; /* TODO: see if the cd-rom was originally connected there on the real machines emulated by 86Box (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) */ uint8_t cd_dma8 = -1; uint8_t cd_irq = 0; @@ -289,21 +506,10 @@ azt1605_create_config_word(void *priv) switch (azt2316a->cur_addr) { case 0x220: // do nothing -#if 0 - temp += 0 << 0; -#endif break; case 0x240: temp += 1 << 0; break; -#if 0 - case 0x260: // TODO: INVALID? - temp += 2 << 0; - break; - case 0x280: // TODO: INVALID? - temp += 3 << 0; - break; -#endif default: break; } @@ -329,9 +535,6 @@ azt1605_create_config_word(void *priv) switch (azt2316a->cur_wss_addr) { case 0x530: // do nothing -#if 0 - temp += 0 << 16; -#endif break; case 0x604: temp += 1 << 16; @@ -350,15 +553,12 @@ azt1605_create_config_word(void *priv) if (azt2316a->cur_wss_enabled) temp += 1 << 18; - if (game_enable) + if (azt2316a->gameport_enabled) temp += 1 << 4; switch (azt2316a->cur_mpu401_addr) { case 0x300: // do nothing -#if 0 - temp += 0 << 2; -#endif break; case 0x330: temp += 1 << 2; @@ -372,9 +572,8 @@ azt1605_create_config_word(void *priv) temp += 1 << 3; switch (cd_type) { - case 0: /* disabled - do nothing - temp += 0 << 5; */ + case 0: // disabled + // do nothing break; case 1: // panasonic temp += 1 << 5; @@ -403,9 +602,8 @@ azt1605_create_config_word(void *priv) } switch (cd_dma8) { - case 0xFF: /* -1 - do nothing - temp += 0 << 22;*/ + case 0xFF: // -1 + //do nothing break; case 0: temp += 1 << 22; @@ -468,7 +666,6 @@ azt2316a_create_config_word(void *priv) uint32_t temp = 0; /* not implemented / hardcoded */ - uint8_t game_enable = 1; uint16_t cd_addr = 0x310; uint8_t cd_type = 0; /* TODO: see if the cd-rom was originally connected there on the real machines emulated by 86Box (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) */ uint8_t cd_dma8 = -1; @@ -480,24 +677,18 @@ azt2316a_create_config_word(void *priv) return; } + if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + aztpr16_create_config_word(priv); + return; + } + switch (azt2316a->cur_addr) { case 0x220: // do nothing -#if 0 - temp += 0 << 0; -#endif break; case 0x240: temp += 1 << 0; break; -#if 0 - case 0x260: // TODO: INVALID? - temp += 2 << 0; - break; - case 0x280: // TODO: INVALID? - temp += 3 << 0; - break; -#endif default: break; } @@ -521,13 +712,6 @@ azt2316a_create_config_word(void *priv) } switch (azt2316a->cur_dma) { -#if 0 - // TODO: INVALID? - case 0xFF: // -1 - // do nothing - //temp += 0 << 6; - break; -#endif case 0: temp += 1 << 6; break; @@ -545,9 +729,6 @@ azt2316a_create_config_word(void *priv) switch (azt2316a->cur_wss_addr) { case 0x530: // do nothing -#if 0 - temp += 0 << 8; -#endif break; case 0x604: temp += 1 << 8; @@ -564,14 +745,11 @@ azt2316a_create_config_word(void *priv) } if (azt2316a->cur_wss_enabled) temp += 1 << 10; - if (game_enable) + if (azt2316a->gameport_enabled) temp += 1 << 11; switch (azt2316a->cur_mpu401_addr) { case 0x300: // do nothing -#if 0 - temp += 0 << 12; -#endif break; case 0x330: temp += 1 << 12; @@ -587,9 +765,6 @@ azt2316a_create_config_word(void *priv) switch (cd_addr) { case 0x310: // do nothing -#if 0 - temp += 0 << 14; -#endif break; case 0x320: temp += 1 << 14; @@ -607,9 +782,6 @@ azt2316a_create_config_word(void *priv) switch (cd_type) { case 0: /* disabled */ // do nothing -#if 0 - temp += 0 << 16; */ -#endif break; case 1: /* panasonic */ temp += 1 << 16; @@ -638,18 +810,15 @@ azt2316a_create_config_word(void *priv) } switch (cd_dma8) { - case 0xFF: /* -1 - do nothing - temp += 0 << 20; */ + case 0xFF: // -1 + //do nothing break; case 0: temp += 1 << 20; break; -#if 0 - case 1: // TODO: INVALID? + case 1: temp += 2 << 20; break; -#endif case 3: temp += 3 << 20; break; @@ -659,9 +828,8 @@ azt2316a_create_config_word(void *priv) } switch (cd_dma16) { - case 0xFF: /* -1 - do nothing - temp += 0 << 22; */ + case 0xFF: // -1 + //do nothing break; case 5: temp += 1 << 22; @@ -826,6 +994,141 @@ azt2316a_config_read(uint16_t addr, void *priv) return temp; } +static void +aztpr16_config_write(uint16_t addr, uint8_t val, void *priv) +{ + azt2316a_t *azt2316a = (azt2316a_t *) priv; + uint8_t temp; + + aztech_log(azt2316a->log, "Aztech PR16 Config Word Write: (%04X) = %02X\n", addr, val); + + if (addr == (azt2316a->cur_addr + 0x404)) { + if (val & 0x80) + azt2316a->config_word_unlocked = 1; + else + azt2316a->config_word_unlocked = 0; + } else if (azt2316a->config_word_unlocked) { + if (val == 0xFF) { + return; + } + switch (addr & 3) { + case 0: + azt2316a->config_word = (azt2316a->config_word & 0xFFFFFF00) | val; + + temp = val & 3; + if (temp == 0) + azt2316a->cur_addr = 0x220; + else if (temp == 1) + azt2316a->cur_addr = 0x240; + else if (temp == 2) + azt2316a->cur_addr = 0x260; + else if (temp == 3) + azt2316a->cur_addr = 0x280; + + if (val & 0x4) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + if (val & 0x8) + azt2316a->cur_mpu401_enabled = 1; + else + azt2316a->cur_mpu401_enabled = 0; + + if (val & 0x10) + azt2316a->gameport_enabled = 1; + else + azt2316a->gameport_enabled = 0; + break; + case 1: + azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) | (val << 8); + + if (val & 0x1) + azt2316a->cur_irq = 2; + else if (val & 0x2) + azt2316a->cur_irq = 5; + else if (val & 0x4) + azt2316a->cur_irq = 7; + else if (val & 0x8) + azt2316a->cur_irq = 10; + /* else undefined? */ + + if (val & 0x10) + azt2316a->cur_mpu401_irq = 2; + else if (val & 0x20) + azt2316a->cur_mpu401_irq = 5; + else if (val & 0x40) + azt2316a->cur_mpu401_irq = 7; + else if (val & 0x80) + azt2316a->cur_mpu401_irq = 10; + /* else undefined? */ + break; + case 2: + azt2316a->config_word = (azt2316a->config_word & 0xFF00FFFF) | (val << 16); + + io_removehandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_removehandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + temp = val & 0x3; + if (temp == 0) + azt2316a->cur_wss_addr = 0x530; + else if (temp == 1) + azt2316a->cur_wss_addr = 0x604; + else if (temp == 2) + azt2316a->cur_wss_addr = 0xE80; + else if (temp == 3) + azt2316a->cur_wss_addr = 0xF40; + + io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + /* no actual effect */ + if (val & 0x4) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + break; + case 3: + azt2316a->config_word = (azt2316a->config_word & 0x00FFFFFF) | (val << 24); + + if (val & 0x01) { + azt2316a->cur_dma = 0; + azt2316a->cur_wss_dma = 0; + } else if (val & 0x02) { + azt2316a->cur_dma = 1; + azt2316a->cur_wss_dma = 1; + } else if (val & 0x04) { + azt2316a->cur_dma = 3; + azt2316a->cur_wss_dma = 3; + } + + if (val & 0x08) + azt2316a->cur_wss_dma16 = 5; + else if (val & 0x10) + azt2316a->cur_wss_dma16 = 6; + else if (val & 0x20) + azt2316a->cur_wss_dma16 = 7; + break; + + default: + break; + } + /* update sbprov2 configs */ + sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); + sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); + sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); + + mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); + mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); + + ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma); + ad1848_setirq(&azt2316a->ad1848, azt2316a->cur_irq); + azt2316a->cur_wss_irq = azt2316a->cur_irq; + + gameport_remap(azt2316a->gameport, (azt2316a->gameport_enabled) ? 0x200 : 0x00); + } +} + static void azt1605_config_write(uint16_t addr, uint8_t val, void *priv) { @@ -840,7 +1143,7 @@ azt1605_config_write(uint16_t addr, uint8_t val, void *priv) else azt2316a->config_word_unlocked = 0; } else if (azt2316a->config_word_unlocked) { - if (val == 0xFF) { /* TODO: check if this still happens on eeprom.sys after having more complete emulation! */ + if (val == 0xFF) { return; } switch (addr & 3) { @@ -852,12 +1155,7 @@ azt1605_config_write(uint16_t addr, uint8_t val, void *priv) azt2316a->cur_addr = 0x220; else if (temp == 1) azt2316a->cur_addr = 0x240; -#if 0 - else if (temp == 2) - azt2316a->cur_addr = 0x260; // TODO: INVALID - else if (temp == 3) - azt2316a->cur_addr = 0x280; // TODO: INVALID -#endif + if (val & 0x4) azt2316a->cur_mpu401_addr = 0x330; else @@ -867,6 +1165,11 @@ azt1605_config_write(uint16_t addr, uint8_t val, void *priv) azt2316a->cur_mpu401_enabled = 1; else azt2316a->cur_mpu401_enabled = 0; + + if (val & 0x10) + azt2316a->gameport_enabled = 1; + else + azt2316a->gameport_enabled = 0; break; case 1: azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) | (val << 8); @@ -929,6 +1232,8 @@ azt1605_config_write(uint16_t addr, uint8_t val, void *priv) mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); + + gameport_remap(azt2316a->gameport, (azt2316a->gameport_enabled) ? 0x200 : 0x00); } } @@ -1000,6 +1305,11 @@ azt2316a_config_write(uint16_t addr, uint8_t val, void *priv) else azt2316a->cur_wss_enabled = 0; + if (val & 0x8) + azt2316a->gameport_enabled = 1; + else + azt2316a->gameport_enabled = 0; + if (val & 0x10) azt2316a->cur_mpu401_addr = 0x330; else @@ -1037,6 +1347,8 @@ azt2316a_config_write(uint16_t addr, uint8_t val, void *priv) mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); + + gameport_remap(azt2316a->gameport, (azt2316a->gameport_enabled) ? 0x200 : 0x00); } } @@ -1062,6 +1374,33 @@ azt2316a_enable_wss(uint8_t enable, void *priv) } } +void +aztpr16_wss_mode(uint8_t mode, void *priv) +{ + azt2316a_t *azt2316a = (azt2316a_t *) priv; + + sound_set_cd_audio_filter(NULL, NULL); + + if (mode) { + azt2316a->cur_mode = 1; + sound_set_cd_audio_filter(ad1848_filter_cd_audio, &azt2316a->ad1848); + azt2316a->sb->opl_mixer = azt2316a; + azt2316a->sb->opl_mix = azt1605_filter_opl; + } + else { + azt2316a->cur_mode = 0; + sound_set_cd_audio_filter(sbpro_filter_cd_audio, azt2316a->sb); + azt2316a->sb->opl_mixer = NULL; + azt2316a->sb->opl_mix = NULL; + } + + if (mode == 0x03) + ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma16); + else + ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma); + +} + static void azt2316a_get_buffer(int32_t *buffer, int len, void *priv) { @@ -1097,6 +1436,8 @@ azt_init(const device_t *info) fn = "azt1605.nvr"; } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { fn = "azt2316a.nvr"; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + fn = "aztpr16.nvr"; } /* config */ @@ -1121,13 +1462,13 @@ azt_init(const device_t *info) if (!loaded_from_eeprom) { if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { - read_eeprom[0] = 0x00; - read_eeprom[1] = 0x00; - read_eeprom[2] = 0x00; - read_eeprom[3] = 0x00; - read_eeprom[4] = 0x00; - read_eeprom[5] = 0x00; - read_eeprom[6] = 0x00; + read_eeprom[0] = 0xee; /* SB Voice mixer value */ + read_eeprom[1] = 0x00; /* SB Mic mixer value (bits 2-0) */ + read_eeprom[2] = 0x00; /* SB Record Source */ + read_eeprom[3] = 0xee; /* SB Master mixer value */ + read_eeprom[4] = 0xee; /* SB FM mixer value */ + read_eeprom[5] = 0xee; /* SB CD mixer value */ + read_eeprom[6] = 0x00; /* SB Line mixer value */ read_eeprom[7] = 0x00; read_eeprom[8] = 0x00; read_eeprom[9] = 0x00; @@ -1154,6 +1495,28 @@ azt_init(const device_t *info) read_eeprom[13] = 0x14; read_eeprom[14] = 0x04; read_eeprom[15] = 0xFF; /* SBPro Master volume (EMUTSR) */ + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + read_eeprom[0] = 0x00; + read_eeprom[1] = 0x00; + read_eeprom[2] = 0x00; + read_eeprom[3] = 0x3f; /* Master Volume L */ + read_eeprom[4] = 0x3f; /* Master Volume R */ + read_eeprom[5] = 0x1f; /* Wave Volume L */ + read_eeprom[6] = 0x1f; /* Wave Volume R */ + read_eeprom[7] = 0x1f; /* FM Volume L */ + read_eeprom[8] = 0x1f; /* FM Volume R */ + read_eeprom[9] = 0x1f; /* CD Volume L */ + read_eeprom[10] = 0x1f; /* CD Volume R */ + read_eeprom[11] = 0x1f; /* Line Volume L */ + read_eeprom[12] = 0x1f; /* Line Volume R */ + read_eeprom[13] = 0x1f; /* Mic Volume L */ + read_eeprom[14] = 0x1f; /* Mic Volume R */ + read_eeprom[15] = 0x1f; /* WSynth Volume L */ + read_eeprom[16] = 0x1f; /* WSynth Volume R */ + read_eeprom[32] = 0x1c; + read_eeprom[33] = 0x12; + read_eeprom[34] = 0x04; + read_eeprom[35] = 0x02; } } @@ -1218,6 +1581,11 @@ azt_init(const device_t *info) else azt2316a->cur_wss_enabled = 0; + if (azt2316a->config_word & (1 << 11)) + azt2316a->gameport_enabled = 1; + else + azt2316a->gameport_enabled = 0; + if (azt2316a->config_word & (1 << 12)) azt2316a->cur_mpu401_addr = 0x330; else @@ -1267,6 +1635,11 @@ azt_init(const device_t *info) else azt2316a->cur_mpu401_enabled = 0; + if (azt2316a->config_word & (1 << 4)) + azt2316a->gameport_enabled = 1; + else + azt2316a->gameport_enabled = 0; + if (azt2316a->config_word & (1 << 8)) azt2316a->cur_irq = 9; else if (azt2316a->config_word & (1 << 9)) @@ -1312,18 +1685,122 @@ azt_init(const device_t *info) azt2316a->cur_wss_enabled = 0; // these are not present on the EEPROM - azt2316a->cur_dma = device_get_config_int("sb_dma8"); // TODO: investigate TSR to make this work with it - there is no software configurable DMA8? + azt2316a->cur_dma = device_get_config_int("sb_dma8"); azt2316a->cur_wss_irq = device_get_config_int("wss_irq"); azt2316a->cur_wss_dma = device_get_config_int("wss_dma"); azt2316a->cur_mode = 0; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + azt2316a->config_word = read_eeprom[32] + (read_eeprom[33] << 8) + (read_eeprom[34] << 16) + (read_eeprom[35] << 24); + aztech_log(azt2316a->log, "AZTPR16 Config Word = %08X\n", azt2316a->config_word); + + switch (azt2316a->config_word & (3 << 0)) { + case 0: + azt2316a->cur_addr = 0x220; + break; + case 1: + azt2316a->cur_addr = 0x240; + break; + case 2: + azt2316a->cur_addr = 0x260; + break; + case 3: + azt2316a->cur_addr = 0x280; + break; + default: + fatal("AZTPR16: invalid sb addr in config word %08X\n", azt2316a->config_word); + break; + } + + if (azt2316a->config_word & (1 << 2)) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + if (azt2316a->config_word & (1 << 3)) + azt2316a->cur_mpu401_enabled = 1; + else + azt2316a->cur_mpu401_enabled = 0; + + if (azt2316a->config_word & (1 << 4)) + azt2316a->gameport_enabled = 1; + else + azt2316a->gameport_enabled = 0; + + if (azt2316a->config_word & (1 << 8)) + azt2316a->cur_irq = 2; + else if (azt2316a->config_word & (1 << 9)) + azt2316a->cur_irq = 5; + else if (azt2316a->config_word & (1 << 10)) + azt2316a->cur_irq = 7; + else if (azt2316a->config_word & (1 << 11)) + azt2316a->cur_irq = 10; + else + fatal("AZTPR16: invalid sb irq in config word %08X\n", azt2316a->config_word); + + if (azt2316a->config_word & (1 << 12)) + azt2316a->cur_mpu401_irq = 2; + else if (azt2316a->config_word & (1 << 13)) + azt2316a->cur_mpu401_irq = 5; + else if (azt2316a->config_word & (1 << 14)) + azt2316a->cur_mpu401_irq = 7; + else if (azt2316a->config_word & (1 << 15)) + azt2316a->cur_mpu401_irq = 10; + else + fatal("AZTPR16: invalid mpu401 irq in config word %08X\n", azt2316a->config_word); + switch (azt2316a->config_word & (3 << 16)) { + case 0: + azt2316a->cur_wss_addr = 0x530; + break; + case 1 << 16: + azt2316a->cur_wss_addr = 0x604; + break; + case 2 << 16: + azt2316a->cur_wss_addr = 0xE80; + break; + case 3 << 16: + azt2316a->cur_wss_addr = 0xF40; + break; + default: + fatal("AZTPR16: invalid wss addr in config word %08X\n", azt2316a->config_word); + break; + } + + if (azt2316a->config_word & (1 << 18)) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + if (azt2316a->config_word & (1 << 24)) + azt2316a->cur_dma = 0; + else if (azt2316a->config_word & (1 << 25)) + azt2316a->cur_dma = 1; + else if (azt2316a->config_word & (1 << 26)) + azt2316a->cur_dma = 3; + + if (azt2316a->config_word & (1 << 27)) + azt2316a->cur_wss_dma16 = 5; + else if (azt2316a->config_word & (1 << 28)) + azt2316a->cur_wss_dma16 = 6; + else if (azt2316a->config_word & (1 << 29)) + azt2316a->cur_wss_dma16 = 7; + + // these are not present on the EEPROM + azt2316a->cur_wss_irq = azt2316a->cur_irq; + azt2316a->cur_wss_dma = azt2316a->cur_dma; + azt2316a->cur_mode = 0; } - addr_setting = device_get_config_hex16("addr"); - if (addr_setting) - azt2316a->cur_addr = addr_setting; + if (azt2316a->type != SB_SUBTYPE_CLONE_AZTPR16_0X09) { + addr_setting = device_get_config_hex16("addr"); + if (addr_setting) + azt2316a->cur_addr = addr_setting; + } /* wss part */ - ad1848_init(&azt2316a->ad1848, device_get_config_int("codec")); + if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) + ad1848_init(&azt2316a->ad1848, AD1848_TYPE_DEFAULT); /* AZTPR16 has an internal AD1848-compatible (non-Mode 2 capable) WSS codec */ + else + ad1848_init(&azt2316a->ad1848, device_get_config_int("codec")); if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) ad1848_set_cd_audio_channel(&azt2316a->ad1848, (device_get_config_int("codec") == AD1848_TYPE_CS4248) ? AD1848_AUX1 : AD1848_LINE_IN); else @@ -1334,6 +1811,8 @@ azt_init(const device_t *info) if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) io_sethandler(azt2316a->cur_addr + 0x0400, 0x0040, azt2316a_config_read, NULL, NULL, azt2316a_config_write, NULL, NULL, azt2316a); + else if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) + io_sethandler(azt2316a->cur_addr + 0x0400, 0x0010, azt1605_config_read, NULL, NULL, aztpr16_config_write, NULL, NULL, azt2316a); else /* Aztech 1605 only needs 62x/64x */ io_sethandler(azt2316a->cur_addr + 0x0400, 0x0010, azt1605_config_read, NULL, NULL, azt1605_config_write, NULL, NULL, azt2316a); io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); @@ -1395,6 +1874,17 @@ azt_init(const device_t *info) if (device_get_config_int("receive_input")) midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &azt2316a->sb->dsp); + /* Restore SBPro mixer settings from EEPROM on AZT2316A cards */ + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + azt2316a->sb->mixer_sbpro.regs[0x04] = read_eeprom[0]; /* SBPro Voice */ + azt2316a->sb->mixer_sbpro.regs[0x0a] = read_eeprom[1]; /* SBPro Mic */ + azt2316a->sb->mixer_sbpro.regs[0x0c] = read_eeprom[2]; /* SBPro Record Source */ + azt2316a->sb->mixer_sbpro.regs[0x22] = read_eeprom[3]; /* SBPro Master */ + azt2316a->sb->mixer_sbpro.regs[0x26] = read_eeprom[4]; /* SBPro FM */ + azt2316a->sb->mixer_sbpro.regs[0x28] = read_eeprom[5]; /* SBPro CD */ + azt2316a->sb->mixer_sbpro.regs[0x2e] = read_eeprom[6]; /* SBPro Line */ + } + /* Restore WSS mixer settings from EEPROM on AZT1605 cards */ if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { azt2316a->ad1848.regs[0] = read_eeprom[0]; /* WSS ADC L */ @@ -1409,6 +1899,72 @@ azt_init(const device_t *info) azt2316a->ad1848.regs[19] = read_eeprom[9]; /* CS4231 LINE/SB Voice R */ azt2316a->ad1848.regs[26] = read_eeprom[10]; /* CS4231 Mic */ } + /* Restore mixer settings from EEPROM on AZTPR16 cards */ + if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + azt2316a->sb->mixer_sbpro.regs[0x84] = read_eeprom[3]; /* Master L */ + azt2316a->sb->mixer_sbpro.regs[0x86] = read_eeprom[4]; /* Master R */ + azt2316a->sb->mixer_sbpro.regs[0x88] = read_eeprom[5]; /* Wave L */ + azt2316a->sb->mixer_sbpro.regs[0x8a] = read_eeprom[6]; /* Wave R */ + azt2316a->sb->mixer_sbpro.regs[0x8c] = read_eeprom[7]; /* FM L */ + azt2316a->sb->mixer_sbpro.regs[0x8e] = read_eeprom[8]; /* FM R */ + azt2316a->sb->mixer_sbpro.regs[0xa0] = read_eeprom[9]; /* CD L */ + azt2316a->sb->mixer_sbpro.regs[0xa2] = read_eeprom[10]; /* CD R */ + azt2316a->sb->mixer_sbpro.regs[0xa4] = read_eeprom[11]; /* Line L */ + azt2316a->sb->mixer_sbpro.regs[0xa6] = read_eeprom[12]; /* Line R */ + azt2316a->sb->mixer_sbpro.regs[0xa8] = read_eeprom[13]; /* Mic L */ + azt2316a->sb->mixer_sbpro.regs[0xaa] = read_eeprom[14]; /* Mic R */ + azt2316a->sb->mixer_sbpro.regs[0xac] = read_eeprom[15]; /* WSynth L */ + azt2316a->sb->mixer_sbpro.regs[0xae] = read_eeprom[16]; /* WSynth R */ + azt2316a->sb->mixer_sbpro.regs[0xc2] = read_eeprom[18]; /* Speaker */ + azt2316a->sb->mixer_sbpro.regs[0xc4] = read_eeprom[19]; /* Bass */ + azt2316a->sb->mixer_sbpro.regs[0xc6] = read_eeprom[20]; /* Treble */ + azt2316a->sb->mixer_sbpro.regs[0xc8] = read_eeprom[21]; /* I/O settings byte 1 */ + azt2316a->sb->mixer_sbpro.regs[0xca] = read_eeprom[22]; /* I/O settings byte 2 */ + azt2316a->sb->mixer_sbpro.regs[0xcc] = read_eeprom[23]; /* I/O settings byte 3 */ + azt2316a->sb->mixer_sbpro.regs[0xce] = read_eeprom[24]; /* I/O settings byte 4 */ + azt2316a->sb->mixer_sbpro.regs[0xe0] = read_eeprom[25]; /* Record Gain R */ + azt2316a->sb->mixer_sbpro.regs[0xe2] = read_eeprom[26]; /* Record Gain L */ + azt2316a->sb->mixer_sbpro.regs[0xe4] = read_eeprom[27]; /* Output Gain L */ + azt2316a->sb->mixer_sbpro.regs[0xe6] = read_eeprom[28]; /* Output Gain L */ + azt2316a->sb->mixer_sbpro.regs[0xe8] = read_eeprom[29]; /* Output Gain L */ + + /* Sane initial WSS values */ + azt2316a->ad1848.regs[0] = 0x08; /* WSS ADC L */ + azt2316a->ad1848.regs[1] = 0x08; /* WSS ADC R */ + azt2316a->ad1848.regs[2] = 0x08; /* WSS AUX1/CD L */ + azt2316a->ad1848.regs[3] = 0x08; /* WSS AUX1/CD R */ + azt2316a->ad1848.regs[4] = 0x08; /* WSS AUX2/FM L */ + azt2316a->ad1848.regs[5] = 0x08; /* WSS AUX2/FM R */ + azt2316a->ad1848.regs[6] = 0x08; /* WSS DAC L */ + azt2316a->ad1848.regs[7] = 0x08; /* WSS DAC R */ + + /* Set up CD volume table */ + uint8_t c; + double attenuation; + + 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); + + aztpr16_vols_5bits[c] = (attenuation * 65536); + } + + aztpr16_update_mixer(azt2316a); + } + + azt2316a->gameport = gameport_add(&gameport_pnp_device); + gameport_remap(azt2316a->gameport, (azt2316a->gameport_enabled) ? 0x200: 0x00); return azt2316a; } @@ -1425,6 +1981,8 @@ azt_close(void *priv) fn = "azt1605.nvr"; } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { fn = "azt2316a.nvr"; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + fn = "aztpr16.nvr"; } /* always save to eeprom (recover from bad values) */ @@ -1434,7 +1992,6 @@ azt_close(void *priv) checksum += azt2316a->sb->dsp.azt_eeprom[i]; fwrite(azt2316a->sb->dsp.azt_eeprom, AZTECH_EEPROM_SIZE, 1, fp); - // TODO: confirm any models saving mixer settings to EEPROM and implement reading back // TODO: should remember to save wss duplex setting if 86Box has voice recording implemented in the future? Also, default azt2316a->wss_config // TODO: azt2316a->cur_mode is not saved to EEPROM? fwrite(&checksum, sizeof(checksum), 1, fp); @@ -1463,6 +2020,45 @@ azt_speed_changed(void *priv) sb_speed_changed(azt2316a->sb); } +static const device_config_t aztpr16_config[] = { + // clang-format off + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + static const device_config_t azt1605_config[] = { // clang-format off { @@ -1710,3 +2306,17 @@ const device_t azt1605_device = { .force_redraw = NULL, .config = azt1605_config }; + +const device_t aztpr16_device = { + .name = "Aztech Sound Galaxy Pro 16 (AZTPR16)", + .internal_name = "aztpr16", + .flags = DEVICE_ISA16, + .local = SB_SUBTYPE_CLONE_AZTPR16_0X09, + .init = azt_init, + .close = azt_close, + .reset = NULL, + .available = NULL, + .speed_changed = azt_speed_changed, + .force_redraw = NULL, + .config = aztpr16_config +}; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index f041ebb8c..c2193869d 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -43,6 +43,7 @@ #include <86box/timer.h> #include <86box/snd_sb.h> #include <86box/plat_unused.h> +#include <86box/snd_azt2316a.h> #define SB_1 0 #define SB_15 1 @@ -863,6 +864,76 @@ sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *priv) mixer->regs[0x26] = mixer->regs[0x28] = 0xee; mixer->regs[0x2e] = 0x00; sb_dsp_set_stereo(&sb->dsp, mixer->regs[0x0e] & 2); + } else if (sb->dsp.sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + mixer->regs[mixer->index] = val; + sb_log("sb_ct1345: Register WRITE, AZTPR16: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + aztpr16_update_mixer(sb->dsp.parent); + + switch (mixer->index) { + /* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */ + case 0x02: + case 0x06: + case 0x08: + mixer->regs[mixer->index + 0x20] = ((val & 0xe) << 4) | (val & 0xe); + break; + + case 0x22: + case 0x26: + case 0x28: + mixer->regs[mixer->index - 0x20] = (val & 0xe); + break; + + /* More compatibility: + SoundBlaster Pro selects register 020h for 030h, 022h for 032h, + 026h for 036h, and 028h for 038h. */ + case 0x30: + case 0x32: + case 0x36: + case 0x38: + mixer->regs[mixer->index - 0x10] = (val & 0xee); + break; + + case 0x00: + case 0x04: + case 0x0a: + case 0x0c: + case 0x0e: + case 0x2e: + break; + + /* Aztech AZTPR16 mixer */ + case 0x84: + case 0x86: + case 0x88: + case 0x8a: + case 0x8c: + case 0x8e: + case 0xa0: + case 0xa2: + case 0xa4: + case 0xa6: + case 0xa8: + case 0xaa: + case 0xac: + case 0xae: + case 0xc2: + case 0xc4: + case 0xc6: + case 0xc8: + case 0xca: + case 0xcc: + case 0xce: + case 0xe0: + case 0xe2: + case 0xe4: + case 0xe6: + case 0xe8: + break; + + default: + sb_log("sb_ct1345: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } } else { mixer->regs[mixer->index] = val; @@ -967,6 +1038,36 @@ sb_ct1345_mixer_read(uint16_t addr, void *priv) case 0x38: return mixer->regs[mixer->index]; + /* Aztech AZTPR16 mixer */ + case 0x84: + case 0x86: + case 0x88: + case 0x8a: + case 0x8c: + case 0x8e: + case 0xa0: + case 0xa2: + case 0xa4: + case 0xa6: + case 0xa8: + case 0xaa: + case 0xac: + case 0xae: + case 0xc2: + case 0xc4: + case 0xc6: + case 0xc8: + case 0xca: + case 0xcc: + case 0xce: + case 0xe0: + case 0xe2: + case 0xe4: + case 0xe6: + case 0xe8: + if (sb->dsp.sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09) + return mixer->regs[mixer->index]; + default: sb_log("sb_ct1345: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); break; diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index bfc2847ed..8adb46c5d 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -1287,6 +1287,8 @@ sb_exec_command(sb_dsp_t *dsp) sb_add_data(dsp, 0x11); /* AZTECH get type, WASHINGTON/latest - according to devkit. E.g.: The one in the Itautec Infoway Multimidia */ else if ((dsp->sb_data[0] == 0x05 || dsp->sb_data[0] == 0x55) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) sb_add_data(dsp, 0x0C); /* AZTECH get type, CLINTON - according to devkit. E.g.: The one in the Packard Bell Legend 100CD */ + else if ((dsp->sb_data[0] == 0x05 || dsp->sb_data[0] == 0x55) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09) + sb_add_data(dsp, 0x09); /* AZTECH get type, AZTPR16 */ else if (dsp->sb_data[0] == 0x08) { /* EEPROM address to write followed by byte */ if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE) @@ -1307,6 +1309,9 @@ sb_exec_command(sb_dsp_t *dsp) /* HACK: Aztech HWSET seems to rely on RP being incremented for detection to work after EMUTSR is run */ dsp->sb_read_rp++; break; + } else if ((dsp->sb_data[0] == 0x0f) && (dsp->sb_data[1] == 0xff) && (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09)) { + sb_dsp_log("AZTPR16: Command 0x08, Subcommand 0x0f/0xff\n"); + sb_add_data(dsp, 0x80); } else sb_dsp_log("AZT2316A: UNKNOWN 0x08 COMMAND: %02X\n", dsp->sb_data[0]); /* 0x08 (when shutting down, driver tries to read 1 byte of response), 0x55, 0x0D, 0x08D seen */ break; @@ -1324,6 +1329,9 @@ sb_exec_command(sb_dsp_t *dsp) } else if (dsp->sb_data[0] == 0x01) { sb_dsp_log("AZT2316A: SB8PROV2 MODE!\n"); azt2316a_enable_wss(0, dsp->parent); + } else if ((dsp->sb_data[0] == 0x0f) && (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09)) { + sb_dsp_log("AZTPR16: Mode switch command, params = %02X, %02X\n", dsp->sb_data[0], dsp->sb_data[1]); + aztpr16_wss_mode(dsp->sb_data[1], dsp->parent); } else sb_dsp_log("AZT2316A: UNKNOWN MODE! = %02x\n", dsp->sb_data[0]); // sequences 0x02->0xFF, 0x04->0xFF seen } @@ -1738,6 +1746,9 @@ sb_exec_command(sb_dsp_t *dsp) } else if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) { sb_add_data(dsp, 0x2); sb_add_data(dsp, 0x1); + } else if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + sb_add_data(dsp, 0x2); + sb_add_data(dsp, 0x1); } break; } @@ -1948,7 +1959,9 @@ sb_write(uint16_t addr, uint8_t val, void *priv) /* variable length commands */ if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x08) sb_commands[dsp->sb_command] = 3; - else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x07) + else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && (dsp->sb_data[0] == 0x07 || dsp->sb_data[0] == 0x0f)) + sb_commands[dsp->sb_command] = 2; + else if (dsp->sb_command == 0x09 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x0f) sb_commands[dsp->sb_command] = 2; } } @@ -1957,7 +1970,7 @@ sb_write(uint16_t addr, uint8_t val, void *priv) dsp->sb_data_stat = -1; if (IS_AZTECH(dsp)) { /* variable length commands */ - if (dsp->sb_command == 0x08) + if (dsp->sb_command == 0x08 || dsp->sb_command == 0x09) sb_commands[dsp->sb_command] = 1; } } diff --git a/src/sound/sound.c b/src/sound/sound.c index cdb3ec51c..cbf358327 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -147,6 +147,7 @@ static const SOUND_CARD sound_cards[] = { { &ad1816_device }, { &azt2316a_device }, { &azt1605_device }, + { &aztpr16_device }, { &sb_goldfinch_device }, { &cs4232_device }, { &cs4235_device },