diff --git a/src/Makefile.am b/src/Makefile.am index b074a05..4be48a1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,7 +40,7 @@ mca.c mcr.c mem.c mem_bios.c mfm_at.c mfm_xebec.c model.c mouse.c mouse_msystems neat.c nmi.c nvr.c olivetti_m24.c opti495.c paths.c pc.c pc87306.c pci.c pic.c piix.c pit.c ppi.c ps1.c ps2.c ps2_mca.c \ ps2_nvr.c nvr_tc8521.c pzx.c rom.c rtc.c rtc_tc8521.c scamp.c scat.c scsi.c scsi_53c400.c scsi_aha1540.c scsi_cd.c scsi_hd.c \ scsi_ibm.c scsi_zip.c serial.c sio.c sis496.c sl82c460.c sound.c sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_audiopci.c \ -sound_cms.c sound_emu8k.c sound_gus.c sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c \ +sound_azt2316a.c sound_cms.c sound_emu8k.c sound_gus.c sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c \ sound_sb.c sound_sb_dsp.c sound_sn76489.c sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c \ sst39sf010.c tandy_eeprom.c tandy_rom.c t1000.c t3100e.c timer.c um8669f.c um8881f.c vid_ati_eeprom.c vid_ati_mach64.c \ vid_ati18800.c vid_ati28800.c vid_ati68860_ramdac.c vid_cga.c vid_cl5429.c vid_colorplus.c vid_compaq_cga.c vid_ega.c \ diff --git a/src/Makefile.mingw-wx-sdl2 b/src/Makefile.mingw-wx-sdl2 index 8422b25..c129df8 100644 --- a/src/Makefile.mingw-wx-sdl2 +++ b/src/Makefile.mingw-wx-sdl2 @@ -26,7 +26,7 @@ OBJ = 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o 808x.o 82091aa.o acc203 mvp3.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pc87306.o pci.o pic.o \ piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o pzx.o rom.o rtc.o rtc_tc8521.o scamp.o scat.o scsi.o \ scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_ibm.o scsi_zip.o serial.o sio.o sis496.o sl82c460.o \ - sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_dbopl.o \ + sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_azt2316a.o sound_cms.o sound_dbopl.o \ sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o \ sound_resid.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \ sound_ym7128.o soundopenal.o sst39sf010.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o \ diff --git a/src/Makefile.mingw-wx-sdl2-network b/src/Makefile.mingw-wx-sdl2-network index bcce1a5..c6445db 100644 --- a/src/Makefile.mingw-wx-sdl2-network +++ b/src/Makefile.mingw-wx-sdl2-network @@ -26,7 +26,7 @@ OBJ = 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o 808x.o 82091aa.o acc203 mvp3.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pc87306.o pci.o pic.o \ piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o pzx.o rom.o rtc.o rtc_tc8521.o scamp.o scat.o scsi.o \ scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_ibm.o scsi_zip.o serial.o sio.o sis496.o sl82c460.o \ - sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_dbopl.o \ + sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_azt2316a.o sound_cms.o sound_dbopl.o \ sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o \ sound_resid.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \ sound_ym7128.o soundopenal.o sst39sf010.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o \ diff --git a/src/sound.c b/src/sound.c index a5e7320..f038613 100644 --- a/src/sound.c +++ b/src/sound.c @@ -15,6 +15,7 @@ #include "sound_adlib.h" #include "sound_adlibgold.h" #include "sound_audiopci.h" +#include "sound_azt2316a.h" #include "sound_pas16.h" #include "sound_sb.h" #include "sound_sb_dsp.h" @@ -35,23 +36,25 @@ typedef struct static SOUND_CARD sound_cards[] = { - {"None", "none", NULL}, - {"Adlib", "adlib", &adlib_device}, - {"Adlib", "adlib_mca", &adlib_mca_device}, - {"Sound Blaster 1.0", "sb", &sb_1_device}, - {"Sound Blaster 1.5", "sb1.5", &sb_15_device}, - {"Sound Blaster MCV", "sbmcv", &sb_mcv_device}, - {"Sound Blaster 2.0", "sb2.0", &sb_2_device}, - {"Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device}, - {"Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device}, - {"Sound Blaster Pro MCV", "sbpromcv", &sb_pro_mcv_device}, - {"Sound Blaster 16", "sb16", &sb_16_device}, - {"Sound Blaster AWE32", "sbawe32", &sb_awe32_device}, - {"Adlib Gold", "adlibgold", &adgold_device}, - {"Windows Sound System", "wss", &wss_device}, - {"Pro Audio Spectrum 16", "pas16", &pas16_device}, - {"Ensoniq AudioPCI (ES1371)", "es1371", &es1371_device}, - {"Sound Blaster PCI 128", "sbpci128", &es1371_device}, + {"None", "none", NULL}, + {"Adlib", "adlib", &adlib_device}, + {"Adlib", "adlib_mca", &adlib_mca_device}, + {"Sound Blaster 1.0", "sb", &sb_1_device}, + {"Sound Blaster 1.5", "sb1.5", &sb_15_device}, + {"Sound Blaster MCV", "sbmcv", &sb_mcv_device}, + {"Sound Blaster 2.0", "sb2.0", &sb_2_device}, + {"Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device}, + {"Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device}, + {"Sound Blaster Pro MCV", "sbpromcv", &sb_pro_mcv_device}, + {"Sound Blaster 16", "sb16", &sb_16_device}, + {"Sound Blaster AWE32", "sbawe32", &sb_awe32_device}, + {"Adlib Gold", "adlibgold", &adgold_device}, + {"Windows Sound System", "wss", &wss_device}, + {"Aztech Sound Galaxy Pro 16 AB (Washington)", "azt2316a", &azt2316a_device}, + {"Aztech Sound Galaxy Nova 16 Extra (Clinton)", "azt1605", &azt1605_device}, + {"Pro Audio Spectrum 16", "pas16", &pas16_device}, + {"Ensoniq AudioPCI (ES1371)", "es1371", &es1371_device}, + {"Sound Blaster PCI 128", "sbpci128", &es1371_device}, {"", "", NULL} }; diff --git a/src/sound_ad1848.c b/src/sound_ad1848.c index 077611b..91bdcf9 100644 --- a/src/sound_ad1848.c +++ b/src/sound_ad1848.c @@ -4,8 +4,10 @@ #include "pic.h" #include "sound.h" #include "sound_ad1848.h" +#include "x86.h" -static int ad1848_vols[64]; +static int ad1848_vols_6bits[64]; +static uint32_t ad1848_vols_5bits_aux_gain[32]; void ad1848_setirq(ad1848_t *ad1848, int irq) { @@ -21,7 +23,7 @@ uint8_t ad1848_read(uint16_t addr, void *p) { ad1848_t *ad1848 = (ad1848_t *)p; uint8_t temp = 0xff; -// pclog("ad1848_read - addr %04X %04X(%08X):%08X ", addr, CS, cs, pc); + switch (addr & 3) { case 0: /*Index*/ @@ -34,7 +36,10 @@ uint8_t ad1848_read(uint16_t addr, void *p) temp = ad1848->status; break; } -// pclog("return %02X\n", temp); +// if ((addr & 3) == 1 && (ad1848->index & 0x1f) > 0x0f) +// pclog("ad1848_read_EXTENDED - addr %04X %04X(%08X):%08X return %02X\n", addr, CS, cs, cpu_state.pc, temp); +// else +// pclog("ad1848_read - addr %04X %04X(%08X):%08X return %02X\n", addr, CS, cs, cpu_state.pc, temp); return temp; } @@ -42,11 +47,18 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) { ad1848_t *ad1848 = (ad1848_t *)p; double freq; -// pclog("ad1848_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc); + uint32_t new_cd_vol_l, new_cd_vol_r; +// if ((addr & 3) == 0 && (val & 0x1f) > 0x0f) +// pclog("ad1848_write_EXTENDED - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); +// else +// pclog("ad1848_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); switch (addr & 3) { case 0: /*Index*/ - ad1848->index = val & 0xf; + 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; @@ -71,29 +83,49 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) break; case 9: - if (!ad1848->enable && (val & 0x41) == 0x01) - { - if (ad1848->timer_latch) - timer_set_delay_u64(&ad1848->timer, ad1848->timer_latch); - else - timer_set_delay_u64(&ad1848->timer, TIMER_USEC); - } + if (!ad1848->enable && (val & 0x41) == 0x01) + { + if (ad1848->timer_latch) + timer_set_delay_u64(&ad1848->timer, ad1848->timer_latch); + else + timer_set_delay_u64(&ad1848->timer, TIMER_USEC); + } ad1848->enable = ((val & 0x41) == 0x01); if (!ad1848->enable) - { - timer_disable(&ad1848->timer); + { + timer_disable(&ad1848->timer); ad1848->out_l = ad1848->out_r = 0; - } + } break; case 12: + ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; return; case 14: ad1848->count = ad1848->regs[15] | (val << 8); break; + // TODO: see which of the extended registers should be read only } ad1848->regs[ad1848->index] = val; + + if (ad1848->type == AD1848_TYPE_CS4231) // TODO: configure CD volume for CS4248/AD1848 too + { + if (ad1848->regs[0x12] & 0x80) + new_cd_vol_l = 0; + else + new_cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f]; + if (ad1848->regs[0x13] & 0x80) + new_cd_vol_r = 0; + else + new_cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f]; + + // Apparently there is no master volume to modulate here + // (The windows mixer just adjusts all registers at the same + // time when the master slider is adjusted) + sound_set_cd_volume(new_cd_vol_l, new_cd_vol_r); + } + break; case 2: ad1848->status &= 0xfe; @@ -125,7 +157,7 @@ static void ad1848_poll(void *p) timer_advance_u64(&ad1848->timer, TIMER_USEC*1000); ad1848_update(ad1848); - + // TODO: line in, mic, etc... if (ad1848->enable) { int32_t temp; @@ -155,12 +187,12 @@ static void ad1848_poll(void *p) if (ad1848->regs[6] & 0x80) ad1848->out_l = 0; else - ad1848->out_l = (ad1848->out_l * ad1848_vols[ad1848->regs[6] & 0x3f]) >> 16; + 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[ad1848->regs[7] & 0x3f]) >> 16; + ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16; if (ad1848->count < 0) { @@ -179,15 +211,17 @@ static void ad1848_poll(void *p) else { ad1848->out_l = ad1848->out_r = 0; + sound_set_cd_volume(0, 0); // pclog("ad1848_poll : not enable\n"); } } -void ad1848_init(ad1848_t *ad1848) +void ad1848_init(ad1848_t *ad1848, int type) { int c; double attenuation; + ad1848->type = type; ad1848->enable = 0; ad1848->status = 0xcc; @@ -195,15 +229,24 @@ void ad1848_init(ad1848_t *ad1848) ad1848->mce = 0x40; ad1848->regs[0] = ad1848->regs[1] = 0; - ad1848->regs[2] = ad1848->regs[3] = 0x80; + ad1848->regs[2] = ad1848->regs[3] = 0x80; // AZT2316A Line-in ad1848->regs[4] = ad1848->regs[5] = 0x80; - ad1848->regs[6] = ad1848->regs[7] = 0x80; + ad1848->regs[6] = ad1848->regs[7] = 0x80; // AZT2316A Master? ad1848->regs[8] = 0; ad1848->regs[9] = 0x08; ad1848->regs[10] = ad1848->regs[11] = 0; - ad1848->regs[12] = 0xa; + if (ad1848->type == AD1848_TYPE_CS4248 || ad1848->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 (ad1848->type == AD1848_TYPE_CS4231) + { + ad1848->regs[0x12] = ad1848->regs[0x13] = 0x80; // AZT2316A CD + ad1848->regs[0x1A] = 0x80; // AZT2316A Mic + } ad1848->out_l = 0; ad1848->out_r = 0; @@ -220,9 +263,23 @@ void ad1848_init(ad1848_t *ad1848) attenuation = pow(10, attenuation / 10); - ad1848_vols[c] = (int)(attenuation * 65536); -// pclog("ad1848_vols %i = %f %i\n", c, attenuation, ad1848_vols[c]); + ad1848_vols_6bits[c] = (int)(attenuation * 65536); +// pclog("ad1848_vols_6bits %i = %f %i\n", c, attenuation, ad1848_vols_6bits[c]); } - + 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] = (int)(attenuation * 65536); +// pclog("ad1848_vols_5bits_aux_gain %i = %f %i\n", c, attenuation, ad1848_vols_5bits_aux_gain[c]); + } + timer_add(&ad1848->timer, ad1848_poll, ad1848, 0); } diff --git a/src/sound_ad1848.h b/src/sound_ad1848.h index a0c436d..de951d9 100644 --- a/src/sound_ad1848.h +++ b/src/sound_ad1848.h @@ -1,9 +1,13 @@ #include "timer.h" +#define AD1848_TYPE_DEFAULT 0 +#define AD1848_TYPE_CS4248 1 +#define AD1848_TYPE_CS4231 2 + typedef struct ad1848_t { int index; - uint8_t regs[16]; + uint8_t regs[32]; // 16 original + 16 CS4231A extensions uint8_t status; int trd; @@ -20,10 +24,12 @@ typedef struct ad1848_t int freq; pc_timer_t timer; - uint64_t timer_latch; + uint64_t timer_latch; int16_t buffer[MAXSOUNDBUFLEN * 2]; int pos; + + int type; } ad1848_t; void ad1848_setirq(ad1848_t *ad1848, int irq); @@ -35,4 +41,4 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p); void ad1848_update(ad1848_t *ad1848); void ad1848_speed_changed(ad1848_t *ad1848); -void ad1848_init(ad1848_t *ad1848); +void ad1848_init(ad1848_t *ad1848, int type); diff --git a/src/sound_azt2316a.c b/src/sound_azt2316a.c new file mode 100644 index 0000000..b5fda11 --- /dev/null +++ b/src/sound_azt2316a.c @@ -0,0 +1,1620 @@ +/* + * TYPE 0x11: (Washington) + * Aztech MMPRO16AB, + * Aztech Sound Galaxy Pro 16 AB + * Aztech Sound Galaxy Washington 16 + * Packard Bell Sound 16A + * ...and other OEM names + * FCC ID I38-MMSN824 and others + * + * TYPE 0x0C: (Clinton) + * Aztech Sound Galaxy Nova 16 Extra + * Aztech Sound Galaxy Clinton 16 + * Packard Bell Forte 16 + * ...and other OEM names + * + * Also works more or less for drivers of other models with the same chipsets. + * + * Copyright (c) 2020 Eluan Costa Miranda All rights reserved. + * + * 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 3 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, see . + * + * ============================================================================= + * + * The CS4248 DSP used is pin and software compatible with the AD1848. + * I also have one of these cards with a CS4231. The driver talks to the + * emulated card as if it was a CS4231 and I still don't know how to tell the + * drivers to see the CS4248. The CS4231 more advanced features are NOT used, + * just the new input/output channels. Apparently some drivers are hardcoded + * for one or the other, so there is an option for this. + * + * There is lots more to be learned form the Win95 drivers. The Linux driver is + * very straightforward and doesn't do much. + * + * Recording and voice modes in the windows mixer still do nothing in PCem, so + * this is missing. + * + * There is a jumper to load the startup configuration from an EEPROM. This is + * implemented, so any software-configured parameters will be saved. + * + * The CD-ROM interface commands are just ignored, along with gameport. + * The MPU401 is always enabled. + * The OPL3 is always active in some (all?) drivers/cards, so there is no + * configuration for this. + * + * Tested with DOS (driver installation, tools, diagnostics), Win3.1 (driver + * installation, tools), Win95 (driver auto-detection), Win NT 3.1 (driver + * installation), lots of games. + * + * I consider type 0x11 (Washington) to be very well tested. Type 0x0C (Clinton) + * wasn't fully tested, but works well for WSS/Windows. BEWARE that there are + * *too many* driver types and OEM versions for each card. Maybe yours isn't + * emulated or you have the wrong driver. Some features of each card may work + * when using wrong drivers. CODEC selection is also important. + * + * Any updates to the WSS and SBPROV2 sound cards should be synced here when + * appropriate. The WSS was completely cloned here, while the SBPROV2 tends + * to call the original functions, except for initialization. + * + * TODO/Notes: + * -Some stuff still not understood on I/O addresses 0x624 and 0x530-0x533. + * -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 + * out or deleted. Other types of cards with this chipset may need them. + * -Sfademo on the Descent CD fails under Win95, works under DOS, see if it + * happens on real hardware (and OPL3 stops working after the failure) + * -There appears to be some differences in sound volumes bertween MIDI, + * SBPROV2, WSS and OPL3? Also check relationship between the SBPROV2 mixer and + * the WSS mixer! Are they independent? Current mode selects which mixer? Are + * they entangled? + * -Check real hardware to see if advanced, mic boost, etc appear in the mixer? + * -CD-ROM driver shipped with the card (SGIDECD.SYS) checks for model strings. + * I have implemented mine (AZtech CDA 468-02I 4x) in PCem. + * -Descent 2 W95 version can't start cd music. Happens on real hardware. + * Explanation further below. + * -DOSQuake and Descent 2 DOS cd music do not work under Win95. The mode + * selects get truncated and send all zeros for output channel selection and + * volume, Descent 2 also has excess zeros! This is a PCem bug, happens on all + * sound cards. CD audio works in Winquake and Descent 2 DOS setup program. + * -DOSQuake CD audio works under DOS with VIDE-CDD.SYS and SGIDECD.SYS. + * Descent 2 DOS is still mute but volume selection appears to be working. + * Descent 2 fails to launch with SGIDECD.SYS with "Device failed to request + * command". SGIDECD.SYS is the CD-ROM driver included with the sound card + * drivers. My real CD-ROM drive can't read anything so I can't check the + * real behavior of this driver. + * -Some cards just have regular IDE ports while other have proprietary ports. + * The regular IDE ports just have a option to enable an almost-generic CD-ROM + * driver in CONFIG.SYS/AUTOEXEC.BAT (like SGIDECD.SYS) and the onboard port + * is enabled/disabled by jumpers. The proprietary ones also have + * address/dma/irq settings. Since the configuration options are ignored here, + * 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). + * -VOLSET.EXE /S:S is supposed to be a no-op on the MMP16AB? + * -Search for TODO in this file. :-) + * + * Misc things I use to test for regressions: Windows sounds, Descent under + * dos/windows, Descent 2 dos/windows (+ cd music option), Descent 2 W95 + cd + * music, Age of Empires (CD + Midi), cd-audio under Windows + volume, + * cd-audio under dos + volume, Aztech diagnose.exe, Aztech volset /M:3 then + * volset /D, Aztech setmode, mixer (volume + balance) under dos and windows, + * DOSQuake under dos and windows (+ cd music and volumes, + Winquake). + * + * Reason for Descent 2 Win95 CD-Audio not working: + * The game calls auxGetNumDevs() to check if any of the AUX devices has + * caps.wTechnology == AUXCAPS_CDAUDIO, but this fails because the Aztech + * Win95 driver only returns a "Line-In" device. I'm not aware of any other + * game that does this and this is completely unnecessary. Other games that + * play cd audio correctly have the exact *same* initialization code, minus + * this check that only Descent 2 Win95 does. It would work if it just skipped + * this check and progressed with calling mciSendCommand() with + * mciOpenParms.lpstrDeviceType = "cdaudio", like other games do. There are + * some sound cards listed as incompatible in the game's README.TXT file that + * are probably due to this. + */ + +#include +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "io.h" +#include "nvr.h" +#include "pic.h" +#include "sound.h" +#include "sound_ad1848.h" +#include "sound_azt2316a.h" +#include "sound_opl.h" +#include "sound_sb.h" +#include "sound_sb_dsp.h" + +/*530, 11, 3 - 530=23*/ +/*530, 11, 1 - 530=22*/ +/*530, 11, 0 - 530=21*/ +/*530, 10, 1 - 530=1a*/ +/*530, 10, 0 - 530=19*/ +/*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 azt2316a_wss_dma[4] = {0, 0, 1, 3}; +static int azt2316a_wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /* W95 only uses 7-10, others may be wrong */ +//static uint16_t azt2316a_wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40}; + +typedef struct azt2316a_t +{ + int type; + int wss_interrupt_after_config; + + uint8_t wss_config; + + uint16_t cur_addr, cur_wss_addr, cur_mpu401_addr; + + uint8_t cur_irq, cur_dma, opl_emu; // sb + uint8_t cur_wss_enabled, cur_wss_irq, cur_wss_dma; + uint8_t cur_mpu401_irq; + + uint32_t config_word; + uint32_t config_word_unlocked; + + uint8_t cur_mode; + + ad1848_t ad1848; + + sb_t *sb; +} azt2316a_t; + +uint8_t azt2316a_wss_read(uint16_t addr, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint8_t temp; +// pclog("azt2316a_read - addr %04X\n", addr); + // 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 + temp = 4 | (azt2316a->wss_config & 0xC0); +// pclog("return %02X\n", temp); + return temp; +} + +void azt2316a_wss_write(uint16_t addr, uint8_t val, void *p) +{ + int interrupt = 0; + azt2316a_t *azt2316a = (azt2316a_t *)p; +// pclog("azt2316a_write - addr %04X val %02X\n", addr, val); + + if (azt2316a->wss_interrupt_after_config) + if ((azt2316a->wss_config & 0x40) && !(val & 0x40)) // TODO: is this the right edge? + interrupt = 1; + + azt2316a->wss_config = val; + azt2316a->cur_wss_dma = azt2316a_wss_dma[val & 3]; + azt2316a->cur_wss_irq = azt2316a_wss_irq[(val >> 3) & 7]; + ad1848_setdma(&azt2316a->ad1848, azt2316a_wss_dma[val & 3]); + ad1848_setirq(&azt2316a->ad1848, azt2316a_wss_irq[(val >> 3) & 7]); + + if (interrupt) + picint(1 << azt2316a->cur_wss_irq); +} + +// generate a config word based on current settings +void azt1605_create_config_word(void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint32_t temp = 0; + + // not implemented / hardcoded + uint8_t game_enable = 1; + uint8_t mpu401_enable = 1; + uint8_t cd_type = 0; // TODO: see if the cd-rom was originally connected there on the real machines emulated by PCem (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) + uint8_t cd_dma8 = -1; + uint8_t cd_irq = 0; + + switch (azt2316a->cur_addr) + { + case 0x220: + // do nothing + //temp += 0 << 0; + break; + case 0x240: + temp += 1 << 0; + break; +/* + case 0x260: // TODO: INVALID? + temp += 2 << 0; + break; + case 0x280: // TODO: INVALID? + temp += 3 << 0; + break; +*/ + default: + fatal("Bad AZT1605 addr %04X\n", azt2316a->cur_addr); + } + switch (azt2316a->cur_irq) + { + case 2: + temp += 1 << 8; + break; + case 3: + temp += 1 << 9; + break; + case 5: + temp += 1 << 10; + break; + case 7: + temp += 1 << 11; + break; + default: + fatal("Bad AZT1605 irq %02X\n", azt2316a->cur_irq); + } + switch (azt2316a->cur_wss_addr) + { + case 0x530: + // do nothing + //temp += 0 << 16; + break; + case 0x604: + temp += 1 << 16; + break; + case 0xE80: + temp += 2 << 16; + break; + case 0xF40: + temp += 3 << 16; + break; + default: + fatal("Bad AZT1605 WSS addr %04X\n", azt2316a->cur_wss_addr); + } + if (azt2316a->cur_wss_enabled) + temp += 1 << 18; + if (game_enable) + temp += 1 << 4; + switch (azt2316a->cur_mpu401_addr) + { + case 0x300: + // do nothing + //temp += 0 << 2; + break; + case 0x330: + temp += 1 << 2; + break; + default: + fatal("Bad AZT1605 MPU401 addr %04X\n", azt2316a->cur_mpu401_addr); + } + if (mpu401_enable) + 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: + fatal("Bad AZT1605 CD type %02X\n", cd_type); + } + switch (cd_dma8) + { + case 0xFF: // -1 + // do nothing + //temp += 0 << 22; + break; + case 0: + temp += 1 << 22; + break; + case 1: + temp += 2 << 22; + break; + case 3: + temp += 3 << 22; + break; + default: + fatal("Bad AZT1605 cd dma8 %02X\n", cd_dma8); + + } + switch (azt2316a->cur_mpu401_irq) + + { + case 2: + temp += 1 << 12; + break; + case 3: + temp += 1 << 13; + break; + case 5: + temp += 1 << 14; + break; + case 7: + temp += 1 << 15; + break; + default: + fatal("Bad AZT1605 mpu401 irq %02X\n", azt2316a->cur_mpu401_irq); + } + switch (cd_irq) + { + case 0: // disabled + // do nothing + break; + case 11: + temp += 1 << 19; + break; + case 12: + temp += 1 << 20; + break; + case 15: + temp += 1 << 21; + break; + default: + fatal("Bad AZT1605 cd irq %02X\n", cd_irq); + } + + azt2316a->config_word = temp; +} +void azt2316a_create_config_word(void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint32_t temp = 0; + + // not implemented / hardcoded + uint8_t game_enable = 1; + uint8_t mpu401_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 PCem (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) + uint8_t cd_dma8 = -1; + uint8_t cd_dma16 = -1; + uint8_t cd_irq = 15; + + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) + { + azt1605_create_config_word(p); + return; + } + + switch (azt2316a->cur_addr) + { + case 0x220: + // do nothing + //temp += 0 << 0; + break; + case 0x240: + temp += 1 << 0; + break; +/* + case 0x260: // TODO: INVALID? + temp += 2 << 0; + break; + case 0x280: // TODO: INVALID? + temp += 3 << 0; + break; +*/ + default: + fatal("Bad AZT2316A addr %04X\n", azt2316a->cur_addr); + } + switch (azt2316a->cur_irq) + { + case 2: + temp += 1 << 2; + break; + case 5: + temp += 1 << 3; + break; + case 7: + temp += 1 << 4; + break; + case 10: + temp += 1 << 5; + break; + default: + fatal("Bad AZT2316A irq %02X\n", azt2316a->cur_irq); + } + switch (azt2316a->cur_dma) + { +/* + // TODO: INVALID? + case 0xFF: // -1 + // do nothing + //temp += 0 << 6; + break; +*/ + case 0: + temp += 1 << 6; + break; + case 1: + temp += 2 << 6; + break; + case 3: + temp += 3 << 6; + break; + default: + fatal("Bad AZT2316A dma %02X\n", azt2316a->cur_dma); + } + switch (azt2316a->cur_wss_addr) + { + case 0x530: + // do nothing + //temp += 0 << 8; + break; + case 0x604: + temp += 1 << 8; + break; + case 0xE80: + temp += 2 << 8; + break; + case 0xF40: + temp += 3 << 8; + break; + default: + fatal("Bad AZT2316A WSS addr %04X\n", azt2316a->cur_wss_addr); + } + if (azt2316a->cur_wss_enabled) + temp += 1 << 10; + if (game_enable) + temp += 1 << 11; + switch (azt2316a->cur_mpu401_addr) + { + case 0x300: + // do nothing + //temp += 0 << 12; + break; + case 0x330: + temp += 1 << 12; + break; + default: + fatal("Bad AZT2316A MPU401 addr %04X\n", azt2316a->cur_mpu401_addr); + } + if (mpu401_enable) + temp += 1 << 13; + switch (cd_addr) + { + case 0x310: + // do nothing + //temp += 0 << 14; + break; + case 0x320: + temp += 1 << 14; + break; + case 0x340: + temp += 2 << 14; + break; + case 0x350: + temp += 3 << 14; + break; + default: + fatal("Bad AZT2316A CD addr %04X\n", cd_addr); + } + switch (cd_type) + { + case 0: // disabled + // do nothing + //temp += 0 << 16; + break; + case 1: // panasonic + temp += 1 << 16; + break; + case 2: // sony + temp += 2 << 16; + break; + case 3: // mitsumi + temp += 3 << 16; + break; + case 4: // aztech + temp += 4 << 16; + break; + case 5: // unused + temp += 5 << 16; + break; + case 6: // unused + temp += 6 << 16; + break; + case 7: // unused + temp += 7 << 16; + break; + default: + fatal("Bad AZT2316A CD type %02X\n", cd_type); + } + switch (cd_dma8) + { + case 0xFF: // -1 + // do nothing + //temp += 0 << 20; + break; + case 0: + temp += 1 << 20; + break; +/* + case 1: // TODO: INVALID? + temp += 2 << 20; + break; +*/ + case 3: + temp += 3 << 20; + break; + default: + fatal("Bad AZT2316A cd dma8 %02X\n", cd_dma8); + } + switch (cd_dma16) + { + case 0xFF: // -1 + // do nothing + //temp += 0 << 22; + break; + case 5: + temp += 1 << 22; + break; + case 6: + temp += 2 << 22; + break; + case 7: + temp += 3 << 22; + break; + default: + fatal("Bad AZT2316A cd dma16 %02X\n", cd_dma16); + } + switch (azt2316a->cur_mpu401_irq) + + { + case 2: + temp += 1 << 24; + break; + case 5: + temp += 1 << 25; + break; + case 7: + temp += 1 << 26; + break; + case 10: + temp += 1 << 27; + break; + default: + fatal("Bad AZT2316A mpu401 irq %02X\n", azt2316a->cur_mpu401_irq); + } + switch (cd_irq) + { + case 5: + temp += 1 << 28; + break; + case 11: + temp += 1 << 29; + break; + case 12: + temp += 1 << 30; + break; + case 15: + temp += 1 << 31; + break; + default: + fatal("Bad AZT2316A cd irq %02X\n", cd_irq); + } + + azt2316a->config_word = temp; +} + +uint8_t azt2316a_config_read(uint16_t addr, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint8_t temp; +// pclog("azt2316a_config_read - addr %04X\n", addr); + + // Some WSS config here + config change enable bit + // (setting bit 7 and writing back) + if (addr == azt2316a->cur_addr + 0x404) + { + // TODO: what is the real meaning of the read value? + // I got a mention of bit 0x10 for WSS from disassembling the source + // code of the driver, and when playing with the I/O ports on real + // hardware after doing some configuration, but didn't dig into it. + // Bit 0x08 seems to be a busy flag and generates a timeout + // (continuous re-reading when initializing windows 98) + temp = azt2316a->cur_mode ? 0x07 : 0x0F; + if (azt2316a->config_word_unlocked) + temp |= 0x80; + } + else + { + // Rest of config. These are documented in the Linux driver. + switch (addr & 0x3) + { + case 0: + temp = azt2316a->config_word & 0xFF; + break; + case 1: + temp = (azt2316a->config_word >> 8) & 0xFF; + break; + case 2: + temp = (azt2316a->config_word >> 16) & 0xFF; + break; + case 3: + temp = (azt2316a->config_word >> 24) & 0xFF; + break; + } + } + +// pclog("return %02X\n", temp); + return temp; +} + +void azt1605_config_write(uint16_t addr, uint8_t val, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint8_t temp; +// pclog("azt2316a_config_write - addr %04X val %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) // TODO: check if this still happens on eeprom.sys after having more complete emulation! + return; + switch (addr & 0x3) + { + case 0: + azt2316a->config_word = (azt2316a->config_word & 0xFFFFFF00) + val; + + temp = val & 0x3; + if (temp == 0) + azt2316a->cur_addr = 0x220; + else if (temp == 1) + azt2316a->cur_addr = 0x240; +/* + else if (temp == 2) + azt2316a->cur_addr = 0x260; // TODO: INVALID + else if (temp == 3) + azt2316a->cur_addr = 0x280; // TODO: INVALID +*/ + + if (val & 0x4) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + // mpu401_enabled is harcoded + //if (val & 0x8) + // azt2316a->cur_mpu401_enabled = 1; + //else + // azt2316a->cur_mpu401_enabled = 0; + + // game_enabled is hardcoded + //if (val & 0x10) + // azt2316a->cur_game_enabled = 1; + //else + // azt2316a->cur_game_enabled = 0; + + // cd_type is hardcoded + //azt2316a->cur_cd_type = (val >> 5) & 0x7; + 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 = 3; + else if (val & 0x4) + azt2316a->cur_irq = 5; + else if (val & 0x8) + azt2316a->cur_irq = 7; + // else undefined? + + if (val & 0x10) + azt2316a->cur_mpu401_irq = 2; + else if (val & 0x20) + azt2316a->cur_mpu401_irq = 3; + else if (val & 0x40) + azt2316a->cur_mpu401_irq = 5; + else if (val & 0x80) + azt2316a->cur_mpu401_irq = 7; + // 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; + + // cd_irq is hardcoded + //if (val & 0x8) + // azt2316a->cur_cd_irq = 11; + //else if (val & 0x10) + // azt2316a->cur_cd_irq = 12; + //else if (val & 0x20) + // azt2316a->cur_cd_irq = 15; + // else disable? + + // cd_dma8 is hardcoded + //temp = (val >> 6) & 0x3; + //if (temp == 0) + // azt2316a->cur_cd_dma8 = -1; + //else if (temp == 1) + // azt2316a->cur_cd_dma8 = 0; + //else if (temp == 3) + // azt2316a->cur_cd_dma8 = 3; + //else error + break; + case 3: + 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_uart_update_addr(&azt2316a->sb->mpu, azt2316a->cur_mpu401_addr); + mpu401_uart_update_irq(&azt2316a->sb->mpu, azt2316a->cur_mpu401_irq); + } +} +void azt2316a_config_write(uint16_t addr, uint8_t val, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint8_t temp; +// pclog("azt2316a_config_write - addr %04X val %02X\n", addr, val); + + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) + { + azt1605_config_write(addr, val, p); + return; + } + + 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) // TODO: check if this still happens on eeprom.sys after having more complete emulation! + return; + switch (addr & 0x3) + { + case 0: + azt2316a->config_word = (azt2316a->config_word & 0xFFFFFF00) + val; + + temp = val & 0x3; + if (temp == 0) + azt2316a->cur_addr = 0x220; + else if (temp == 1) + azt2316a->cur_addr = 0x240; +/* + else if (temp == 2) + azt2316a->cur_addr = 0x260; // TODO: INVALID + else if (temp == 3) + azt2316a->cur_addr = 0x280; // TODO: INVALID +*/ + + if (val & 0x4) + azt2316a->cur_irq = 2; + else if (val & 0x8) + azt2316a->cur_irq = 5; + else if (val & 0x10) + azt2316a->cur_irq = 7; + else if (val & 0x20) + azt2316a->cur_irq = 10; + // else undefined? + + temp = (val >> 6) & 0x3; +/* + if (temp == 0) + azt2316a->cur_dma = -1; // TODO: INVALID? + else */if (temp == 1) + azt2316a->cur_dma = 0; + else if (temp == 2) + azt2316a->cur_dma = 1; + else if (temp == 3) + azt2316a->cur_dma = 3; + break; + case 1: + azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) + (val << 8); + + 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; + + // game_enabled is hardcoded + //if (val & 0x8) + // azt2316a->cur_game_enabled = 1; + //else + // azt2316a->cur_game_enabled = 0; + + if (val & 0x10) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + // mpu401_enabled is harcoded + //if (val & 0x20) + // azt2316a->cur_mpu401_enabled = 1; + //else + // azt2316a->cur_mpu401_enabled = 0; + + // cd_addr is hardcoded + //temp = (val >> 6) & 0x3; + //if (temp == 0) + // azt2316a->cur_cd_addr = 0x310; + //else if (temp == 1) + // azt2316a->cur_cd_addr = 0x320; + //else if (temp == 2) + // azt2316a->cur_cd_addr = 0x340; + //else if (temp == 3) + // azt2316a->cur_cd_addr = 0x350; + break; + case 2: + azt2316a->config_word = (azt2316a->config_word & 0xFF00FFFF) + (val << 16); + + // cd_type is hardcoded + //azt2316a->cur_cd_type = val & 0x7; + + // cd_dma8 is hardcoded + //temp = (val >> 4) & 0x3; + //if (temp == 0) + // azt2316a->cur_cd_dma8 = -1; + //else if (temp == 1) + // azt2316a->cur_cd_dma8 = 0; + //else if (temp == 2) + // azt2316a->cur_cd_dma8 = 1; + //else if (temp == 3) + // azt2316a->cur_cd_dma8 = 3; + + // cd_dma16 is hardcoded + //temp = (val >> 6) & 0x3; + //if (temp == 0) + // azt2316a->cur_cd_dma16 = -1; + //else if (temp == 1) + // azt2316a->cur_cd_dma16 = 5; + //else if (temp == 2) + // azt2316a->cur_cd_dma16 = 6; + //else if (temp == 3) + // azt2316a->cur_cd_dma16 = 7; + break; + case 3: + azt2316a->config_word = (azt2316a->config_word & 0x00FFFFFF) + (val << 24); + + if (val & 0x1) + azt2316a->cur_mpu401_irq = 2; + else if (val & 0x2) + azt2316a->cur_mpu401_irq = 5; + else if (val & 0x4) + azt2316a->cur_mpu401_irq = 7; + else if (val & 0x8) + azt2316a->cur_mpu401_irq = 10; + // else undefined? + + // cd_irq is hardcoded + //if (val & 0x10) + // azt2316a->cur_cd_irq = 5; + //else if (val & 0x20) + // azt2316a->cur_cd_irq = 11; + //else if (val & 0x40) + // azt2316a->cur_cd_irq = 12; + //else if (val & 0x80) + // azt2316a->cur_cd_irq = 15; + // else undefined? + 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_uart_update_addr(&azt2316a->sb->mpu, azt2316a->cur_mpu401_addr); + mpu401_uart_update_irq(&azt2316a->sb->mpu, azt2316a->cur_mpu401_irq); + } +} + +// How it behaves when one or another is activated may affect games auto-detecting (and will also use more of the limited system resources!) +void azt2316a_enable_wss(uint8_t enable, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + + if (enable) + { + azt2316a->cur_mode = 1; + if (!azt2316a->cur_wss_enabled) + { +// apparently it doesn't work like this! +// azt2316a->cur_wss_enabled = 1; +// azt2316a->config_word |= 1 << 10; + } + } + else + { + azt2316a->cur_mode = 0; + if (azt2316a->cur_wss_enabled) + { +// apparently it doesn't work like this! +// azt2316a->cur_wss_enabled = 0; +// azt2316a->config_word &= 0xFFFFFFFF - (1 << 10); + } + } +} + +static void azt2316a_get_buffer(int32_t *buffer, int len, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + + int c; + + // wss part + ad1848_update(&azt2316a->ad1848); + for (c = 0; c < len * 2; c++) + { + buffer[c] += (azt2316a->ad1848.buffer[c] / 2); + } + + azt2316a->ad1848.pos = 0; + + // sbprov2 part + sb_get_buffer_sbpro(buffer, len, azt2316a->sb); +} + +void *azt_common_init(const int type, char *nvr_filename) +{ + int i; + int loaded_from_eeprom = 0; + uint16_t addr_setting; + uint8_t read_eeprom[AZTECH_EEPROM_SIZE]; + azt2316a_t *azt2316a = malloc(sizeof(azt2316a_t)); + memset(azt2316a, 0, sizeof(azt2316a_t)); + + // load configs from eeprom + FILE *f; + f = nvrfopen(nvr_filename, "rb"); + if (f) + { + uint8_t checksum = 0x7F; + uint8_t saved_checksum; + size_t res; // avoid warning + + res = fread(read_eeprom, AZTECH_EEPROM_SIZE, 1, f); + for (i = 0; i < AZTECH_EEPROM_SIZE; i++) + checksum += read_eeprom[i]; + + res = fread(&saved_checksum, sizeof(saved_checksum), 1, f); + (void)res; + + fclose(f); + + if (checksum == saved_checksum) + loaded_from_eeprom = 1; + } + + // no eeprom saved or invalid checksum, load defaults + if (!loaded_from_eeprom) + { + if (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[7] = 0x00; + read_eeprom[8] = 0x00; + read_eeprom[9] = 0x00; + read_eeprom[10] = 0x00; + read_eeprom[11] = 0x88; + read_eeprom[12] = 0xbc; + read_eeprom[13] = 0x00; + read_eeprom[14] = 0x01; + read_eeprom[15] = 0x00; + } + else if (type == SB_SUBTYPE_CLONE_AZT1605_0X0C) + { + read_eeprom[0] = 0x80; + read_eeprom[1] = 0x80; + read_eeprom[2] = 0x9F; + read_eeprom[3] = 0x13; + read_eeprom[4] = 0x16; + read_eeprom[5] = 0x13; + read_eeprom[6] = 0x00; + read_eeprom[7] = 0x00; + read_eeprom[8] = 0x16; + read_eeprom[9] = 0x0B; + read_eeprom[10] = 0x06; + read_eeprom[11] = 0x01; + read_eeprom[12] = 0x1C; + read_eeprom[13] = 0x14; + read_eeprom[14] = 0x04; + read_eeprom[15] = 0x1C; + } + else + fatal("Aztech: unknown type %d\n", type); + } + + // restore settings from EEPROM bytes + if (type == SB_SUBTYPE_CLONE_AZT2316A_0X11) + { + azt2316a->config_word = read_eeprom[11] + (read_eeprom[12] << 8) + (read_eeprom[13] << 16) + (read_eeprom[14] << 24); + switch (azt2316a->config_word & (3 << 0)) + { + case 0: + azt2316a->cur_addr = 0x220; + break; + case 1: + azt2316a->cur_addr = 0x240; + break; + default: + fatal("AZT2316A: invalid sb addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 2)) + azt2316a->cur_irq = 2; + else if (azt2316a->config_word & (1 << 3)) + azt2316a->cur_irq = 5; + else if (azt2316a->config_word & (1 << 4)) + azt2316a->cur_irq = 7; + else if (azt2316a->config_word & (1 << 5)) + azt2316a->cur_irq = 10; + else + fatal("AZT2316A: invalid sb irq in config word %08X\n", azt2316a->config_word); + + switch (azt2316a->config_word & (3 << 6)) + { + case 1 << 6: + azt2316a->cur_dma = 0; + break; + case 2 << 6: + azt2316a->cur_dma = 1; + break; + case 3 << 6: + azt2316a->cur_dma = 3; + break; + default: + fatal("AZT2316A: invalid sb dma in config word %08X\n", azt2316a->config_word); + } + + switch (azt2316a->config_word & (3 << 8)) + { + case 0: + azt2316a->cur_wss_addr = 0x530; + break; + case 1 << 8: + azt2316a->cur_wss_addr = 0x604; + break; + case 2 << 8: + azt2316a->cur_wss_addr = 0xE80; + break; + case 3 << 8: + azt2316a->cur_wss_addr = 0xF40; + break; + default: + fatal("AZT2316A: invalid wss addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 10)) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + // game_enabled is hardcoded + //if (azt2316a->config_word & (1 << 11)) + // azt2316a->cur_game_enabled = 1; + //else + // azt2316a->cur_game_enabled = 0; + + if (azt2316a->config_word & (1 << 12)) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + // mpu401_enabled is hardcoded + //if (azt2316a->config_word & (1 << 13)) + // azt2316a->cur_mpu401_enabled = 1; + //else + // azt2316a->cur_mpu401_enabled = 0; + + // cd_addr is hardcoded + //switch (azt2316a->config_word & (3 << 14)) + //{ + // case 0: + // azt2316a->cur_cd_addr = 0x310; + // break; + // case 1 << 14: + // azt2316a->cur_cd_addr = 0x320; + // break; + // case 2 << 14: + // azt2316a->cur_cd_addr = 0x340; + // break; + // case 3 << 14: + // azt2316a->cur_cd_addr = 0x350; + // break; + // default: + // fatal("AZT2316A: invalid cd addr in config word %08X\n", azt2316a->config_word); + //} + + // cd_type is hardcoded + //azt2316a->cur_cd_type = (azt2316a->config_word >> 16) & 0x7; + + // cd_dma8 is hardcoded + //switch (azt2316a->config_word & (3 << 20)) + //{ + // case 0: + // azt2316a->cur_cd_dma8 = -1; + // break; + // case 1 << 20: + // azt2316a->cur_cd_dma8 = 0; + // break; + // case 2 << 20: + // azt2316a->cur_cd_dma8 = 1; + // break; + // case 3 << 20: + // azt2316a->cur_cd_dma8 = 3; + // break; + // default: + // fatal("AZT2316A: invalid cd dma8 in config word %08X\n", azt2316a->config_word); + //} + + // cd_dma16 is hardcoded + //switch (azt2316a->config_word & (3 << 22)) + //{ + // case 0: + // azt2316a->cur_cd_dma16 = -1; + // break; + // case 1 << 22: + // azt2316a->cur_cd_dma16 = 5; + // break; + // case 2 << 22: + // azt2316a->cur_cd_dma16 = 6; + // break; + // case 3 << 22: + // azt2316a->cur_cd_dma16 = 7; + // break; + // default: + // fatal("AZT2316A: invalid cd dma16 in config word %08X\n", azt2316a->config_word); + //} + + if (azt2316a->config_word & (1 << 24)) + azt2316a->cur_mpu401_irq = 2; + else if (azt2316a->config_word & (1 << 25)) + azt2316a->cur_mpu401_irq = 5; + else if (azt2316a->config_word & (1 << 26)) + azt2316a->cur_mpu401_irq = 7; + else if (azt2316a->config_word & (1 << 27)) + azt2316a->cur_mpu401_irq = 10; + else + fatal("AZT2316A: invalid mpu401 irq in config word %08X\n", azt2316a->config_word); + + // cd_irq is hardcoded + //if (azt2316a->config_word & (1 << 28)) + // azt2316a->cur_cd_irq = 5; + //else if (azt2316a->config_word & (1 << 29)) + // azt2316a->cur_cd_irq = 11; + //else if (azt2316a->config_word & (1 << 30)) + // azt2316a->cur_cd_irq = 12; + //else if (azt2316a->config_word & (1 << 31)) + // azt2316a->cur_cd_irq = 15; + //else + // fatal("AZT2316A: invalid cd irq in config word %08X\n", azt2316a->config_word); + + // these are not present on the EEPROM + azt2316a->cur_wss_irq = 10; + azt2316a->cur_wss_dma = 0; + azt2316a->cur_mode = 0; + } + else if (type == SB_SUBTYPE_CLONE_AZT1605_0X0C) + { + azt2316a->config_word = read_eeprom[12] + (read_eeprom[13] << 8) + (read_eeprom[14] << 16); + switch (azt2316a->config_word & (3 << 0)) + { + case 0: + azt2316a->cur_addr = 0x220; + break; + case 1: + azt2316a->cur_addr = 0x240; + break; + default: + fatal("AZT1605: invalid sb addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 2)) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + // mpu401_enabled is hardcoded + //if (azt2316a->config_word & (1 << 3)) + // azt2316a->cur_mpu401_enabled = 1; + //else + // azt2316a->cur_mpu401_enabled = 0; + + // game_enabled is hardcoded + //if (azt2316a->config_word & (1 << 4)) + // azt2316a->cur_game_enabled = 1; + //else + // azt2316a->cur_game_enabled = 0; + + // cd_type is hardcoded + //azt2316a->cur_cd_type = (azt2316a->config_word >> 5) & 0x7; + + if (azt2316a->config_word & (1 << 8)) + azt2316a->cur_irq = 2; + else if (azt2316a->config_word & (1 << 9)) + azt2316a->cur_irq = 3; + else if (azt2316a->config_word & (1 << 10)) + azt2316a->cur_irq = 5; + else if (azt2316a->config_word & (1 << 11)) + azt2316a->cur_irq = 7; + else + fatal("AZT1605: 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 = 3; + else if (azt2316a->config_word & (1 << 14)) + azt2316a->cur_mpu401_irq = 5; + else if (azt2316a->config_word & (1 << 15)) + azt2316a->cur_mpu401_irq = 7; + else + fatal("AZT1605: 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("AZT1605: invalid wss addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 18)) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + // cd_irq is hardcoded + //if (azt2316a->config_word & (1 << 19)) + // azt2316a->cur_cd_irq = 11; + //else if (azt2316a->config_word & (1 << 20)) + // azt2316a->cur_cd_irq = 12; + //else if (azt2316a->config_word & (1 << 21)) + // azt2316a->cur_cd_irq = 15; + //else + // fatal("AZT1605: invalid cd irq in config word %08X\n", azt2316a->config_word); + + // cd_dma8 is hardcoded + //switch (azt2316a->config_word & (3 << 22)) + //{ + // case 0: + // azt2316a->cur_cd_dma8 = -1; + // break; + // case 1 << 22: + // azt2316a->cur_cd_dma8 = 0; + // break; + // case 2 << 22: + // azt2316a->cur_cd_dma8 = 1; + // break; + // case 3 << 22: + // azt2316a->cur_cd_dma8 = 3; + // break; + // default: + // fatal("AZT1605: invalid cd dma8 in config word %08X\n", azt2316a->config_word); + //} + + // these are not present on the EEPROM + azt2316a->cur_dma = 1; // TODO: investigate TSR to make this work with it - there is no software configurable DMA8? + azt2316a->cur_wss_irq = 10; + azt2316a->cur_wss_dma = 0; + azt2316a->cur_mode = 0; + } + else + fatal("Aztech: unknown type %d\n", type); + + // check for sb addr override jumper + addr_setting = device_get_config_int("addr"); + if (addr_setting) + azt2316a->cur_addr = addr_setting; + + // now we can continue initializing + azt2316a->opl_emu = device_get_config_int("opl_emu"); + azt2316a->wss_interrupt_after_config = device_get_config_int("wss_interrupt_after_config"); + + azt2316a->type = type; + + // wss part + ad1848_init(&azt2316a->ad1848, device_get_config_int("codec")); + + ad1848_setirq(&azt2316a->ad1848, azt2316a->cur_wss_irq); + ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma); + + io_sethandler(azt2316a->cur_addr + 0x0400, 0x0040, azt2316a_config_read, NULL, NULL, azt2316a_config_write, NULL, NULL, azt2316a); + 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); + + // sbprov2 part + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + + 2x8, 2x9, 388 and 389 FM chip (9 voices).*/ + azt2316a->sb = malloc(sizeof(sb_t)); + memset(azt2316a->sb, 0, sizeof(sb_t)); + + for (i = 0; i < AZTECH_EEPROM_SIZE; i++) + azt2316a->sb->dsp.azt_eeprom[i] = read_eeprom[i]; + + azt2316a->sb->opl_emu = azt2316a->opl_emu; + opl3_init(&azt2316a->sb->opl, azt2316a->sb->opl_emu); + sb_dsp_init(&azt2316a->sb->dsp, SBPRO2, azt2316a->type, azt2316a); + 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); + sb_ct1345_mixer_reset(azt2316a->sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + io_sethandler(azt2316a->cur_addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); + io_sethandler(azt2316a->cur_addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); + io_sethandler(azt2316a->cur_addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, azt2316a->sb); + mpu401_uart_init(&azt2316a->sb->mpu, azt2316a->cur_mpu401_addr, azt2316a->cur_mpu401_irq); + + azt2316a_create_config_word(azt2316a); // recreate even if we have read it from EEPROM, because we have some overrides (CD interfaces always off, etc) + sound_add_handler(azt2316a_get_buffer, azt2316a); + + return azt2316a; +} + +void *azt2316a_init() +{ + return azt_common_init(SB_SUBTYPE_CLONE_AZT2316A_0X11, "azt2316a.nvr"); +} + +void *azt1605_init() +{ + return azt_common_init(SB_SUBTYPE_CLONE_AZT1605_0X0C, "azt1605.nvr"); +} + +void azt_common_close(void *p, char *nvr_filename) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + int i; + uint8_t checksum = 0x7F; + + // always save to eeprom (recover from bad values) + FILE *f = nvrfopen(nvr_filename, "wb"); + if (f) + { + for (i = 0; i < AZTECH_EEPROM_SIZE; i++) + checksum += azt2316a->sb->dsp.azt_eeprom[i]; + fwrite(azt2316a->sb->dsp.azt_eeprom, AZTECH_EEPROM_SIZE, 1, f); + + // TODO: confirm any models saving mixer settings to EEPROM and implement reading back + // TODO: should remember to save wss duplex setting if PCem 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, f); + + fclose(f); + } + + sb_close(azt2316a->sb); + + free(azt2316a); +} + +void azt2316a_close(void *p) +{ + azt_common_close(p, "azt2316a.nvr"); +} + +void azt1605_close(void *p) +{ + azt_common_close(p, "azt1605.nvr"); +} + +void azt2316a_speed_changed(void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + + ad1848_speed_changed(&azt2316a->ad1848); + sb_speed_changed(azt2316a->sb); +} + +void azt2316a_add_status_info(char *s, int max_len, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + + sb_dsp_add_status_info(s, max_len, &azt2316a->sb->dsp); +} + +static device_config_t azt2316a_config[] = +{ + { + .name = "codec", + .description = "CODEC", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "CS4248", + .value = AD1848_TYPE_CS4248 + }, + { + .description = "CS4231", + .value = AD1848_TYPE_CS4231 + }, + }, + .default_int = AD1848_TYPE_CS4248 + }, + { + .name = "wss_interrupt_after_config", + .description = "Raise CODEC interrupt on CODEC setup (needed by some drivers)", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "addr", + .description = "SB Address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "Use EEPROM setting", + .value = 0 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .name = "midi", + .description = "MIDI out device", + .type = CONFIG_MIDI, + .default_int = 0 + }, + { + .name = "opl_emu", + .description = "OPL emulator", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DBOPL", + .value = OPL_DBOPL + }, + { + .description = "NukedOPL", + .value = OPL_NUKED + }, + }, + .default_int = OPL_DBOPL + }, + { + .type = -1 + } +}; + +device_t azt2316a_device = +{ + "Aztech Sound Galaxy Pro 16 AB (Washington)", + 0, + azt2316a_init, + azt2316a_close, + NULL, + azt2316a_speed_changed, + NULL, + azt2316a_add_status_info, + azt2316a_config +}; + +device_t azt1605_device = +{ + "Aztech Sound Galaxy Nova 16 Extra (Clinton)", + DEVICE_NOT_WORKING, + azt1605_init, + azt1605_close, + NULL, + azt2316a_speed_changed, + NULL, + azt2316a_add_status_info, + azt2316a_config +}; diff --git a/src/sound_azt2316a.h b/src/sound_azt2316a.h new file mode 100644 index 0000000..2b7d7fa --- /dev/null +++ b/src/sound_azt2316a.h @@ -0,0 +1,4 @@ +extern device_t azt2316a_device; +extern device_t azt1605_device; + +void azt2316a_enable_wss(uint8_t enable, void *p); diff --git a/src/sound_emu8k.h b/src/sound_emu8k.h index 4094863..85eeea6 100644 --- a/src/sound_emu8k.h +++ b/src/sound_emu8k.h @@ -1,3 +1,5 @@ +#ifndef SOUND_EMU8K_H +#define SOUND_EMU8K_H /* All these defines are in samples, not in bytes. */ #define EMU8K_MEM_ADDRESS_MASK 0xFFFFFF @@ -773,3 +775,5 @@ Treble Parameters: 0xD308 0xD308 0xD308 0xD308 0xD308 0xD308 0xD3019 0xD32A 0xD34C 0xD36E 0xD36E 0xD36E 0x0001 0x0001 0x0001 0x0001 0x0001 0x0002 0x0002 0x0002 0x0002 0x0002 0x0002 0x0002 */ + +#endif /* SOUND_EMU8K_H */ diff --git a/src/sound_mpu401_uart.c b/src/sound_mpu401_uart.c index b75cfa8..6ec3614 100644 --- a/src/sound_mpu401_uart.c +++ b/src/sound_mpu401_uart.c @@ -1,5 +1,6 @@ #include "ibm.h" #include "io.h" +#include "pic.h" #include "plat-midi.h" #include "sound_mpu401_uart.h" @@ -9,6 +10,14 @@ enum STATUS_INPUT_NOT_READY = 0x80 }; +static void mpu401_uart_raise_irq(void *p) +{ + mpu401_uart_t *mpu = (mpu401_uart_t *)p; + + if (mpu->irq != -1) + picint(1 << mpu->irq); +} + static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p) { mpu401_uart_t *mpu = (mpu401_uart_t *)p; @@ -18,15 +27,20 @@ static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p) switch (val) { case 0xff: /*Reset*/ + // From Roland: "An ACK will not be sent back upon sending a SYSTEM RESET to leave the UART MODE ($3F)." + // But actual behaviour is weird. For example, the MPU401 port test in the AZT1605 drivers for Windows NT + // want this to return an Ack but the IRQ test in the same driver wants this to raise no interrupts! mpu->rx_data = 0xfe; /*Acknowledge*/ - mpu->status = 0; + mpu->status = STATUS_OUTPUT_NOT_READY; mpu->uart_mode = 0; + //mpu401_uart_raise_irq(p); break; case 0x3f: /*Enter UART mode*/ mpu->rx_data = 0xfe; /*Acknowledge*/ - mpu->status = 0; + mpu->status = STATUS_OUTPUT_NOT_READY; mpu->uart_mode = 1; + mpu401_uart_raise_irq(p); break; } return; @@ -45,14 +59,30 @@ static uint8_t mpu401_uart_read(uint16_t addr, void *p) return mpu->status; /*Data*/ - mpu->status |= STATUS_INPUT_NOT_READY; + mpu->status = STATUS_INPUT_NOT_READY; return mpu->rx_data; } -void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr) +void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr, int irq) { mpu->status = STATUS_INPUT_NOT_READY; mpu->uart_mode = 0; + mpu->addr = addr; + mpu->irq = irq; io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); } + +void mpu401_uart_update_addr(mpu401_uart_t *mpu, uint16_t addr) +{ + io_removehandler(mpu->addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); + mpu->addr = addr; + if (addr != 0) + io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); +} + +void mpu401_uart_update_irq(mpu401_uart_t *mpu, int irq) +{ + mpu->irq = irq; +} + diff --git a/src/sound_mpu401_uart.h b/src/sound_mpu401_uart.h index 91f4119..b133d80 100644 --- a/src/sound_mpu401_uart.h +++ b/src/sound_mpu401_uart.h @@ -1,9 +1,18 @@ +#ifndef SOUND_MPU401_UART +#define SOUND_MPU401_UART + typedef struct mpu401_uart_t { uint8_t status; uint8_t rx_data; - int uart_mode; + int uart_mode; + uint16_t addr; + int irq; } mpu401_uart_t; -void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr); +void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr, int irq); +void mpu401_uart_update_addr(mpu401_uart_t *mpu, uint16_t addr); +void mpu401_uart_update_irq(mpu401_uart_t *mpu, int irq); + +#endif /* SOUND_MPU401_UART */ diff --git a/src/sound_pas16.c b/src/sound_pas16.c index d55b921..e88ec2e 100644 --- a/src/sound_pas16.c +++ b/src/sound_pas16.c @@ -737,7 +737,7 @@ void *pas16_init() memset(pas16, 0, sizeof(pas16_t)); opl3_init(&pas16->opl, 0); - sb_dsp_init(&pas16->dsp, SB2); + sb_dsp_init(&pas16->dsp, SB2, SB_SUBTYPE_DEFAULT, pas16); io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16); diff --git a/src/sound_sb.c b/src/sound_sb.c index 58d0297..e2aa7f3 100644 --- a/src/sound_sb.c +++ b/src/sound_sb.c @@ -21,102 +21,6 @@ FILE* soundfsb = 0/*NULL*/; FILE* soundfsbin = 0/*NULL*/; #endif - - -/* SB 2.0 CD version */ -typedef struct sb_ct1335_mixer_t -{ - int32_t master; - int32_t voice; - int32_t fm; - int32_t cd; - - uint8_t index; - uint8_t regs[256]; -} sb_ct1335_mixer_t; -/* SB PRO */ -typedef struct sb_ct1345_mixer_t -{ - int32_t master_l, master_r; - int32_t voice_l, voice_r; - int32_t fm_l, fm_r; - int32_t cd_l, cd_r; - int32_t line_l, line_r; - int32_t mic; - /*see sb_ct1745_mixer for values for input selector*/ - int32_t input_selector; - - int input_filter; - int in_filter_freq; - int output_filter; - - int stereo; - int stereo_isleft; - - uint8_t index; - uint8_t regs[256]; - -} sb_ct1345_mixer_t; -/* SB16 and AWE32 */ -typedef struct sb_ct1745_mixer_t -{ - int32_t master_l, master_r; - int32_t voice_l, voice_r; - int32_t fm_l, fm_r; - int32_t cd_l, cd_r; - int32_t line_l, line_r; - int32_t mic; - int32_t speaker; - - int bass_l, bass_r; - int treble_l, treble_r; - - int output_selector; - #define OUTPUT_MIC 1 - #define OUTPUT_CD_R 2 - #define OUTPUT_CD_L 4 - #define OUTPUT_LINE_R 8 - #define OUTPUT_LINE_L 16 - - int input_selector_left; - int input_selector_right; - #define INPUT_MIC 1 - #define INPUT_CD_R 2 - #define INPUT_CD_L 4 - #define INPUT_LINE_R 8 - #define INPUT_LINE_L 16 - #define INPUT_MIDI_R 32 - #define INPUT_MIDI_L 64 - - int mic_agc; - - int32_t input_gain_L; - int32_t input_gain_R; - int32_t output_gain_L; - int32_t output_gain_R; - - uint8_t index; - uint8_t regs[256]; -} sb_ct1745_mixer_t; - -typedef struct sb_t -{ - opl_t opl; - sb_dsp_t dsp; - union { - sb_ct1335_mixer_t mixer_sb2; - sb_ct1345_mixer_t mixer_sbpro; - sb_ct1745_mixer_t mixer_sb16; - }; - mpu401_uart_t mpu; - emu8k_t emu8k; - - int pos; - - uint8_t pos_regs[8]; - - int opl_emu; -} sb_t; /* 0 to 7 -> -14dB to 0dB i 2dB steps. 8 to 15 -> 0 to +14dB in 2dB steps. Note that for positive dB values, this is not amplitude, it is amplitude-1. */ const float sb_bass_treble_4bits[]= { @@ -195,7 +99,7 @@ static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p) sb->dsp.pos = 0; } -static void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) +void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) { sb_t *sb = (sb_t *)p; sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; @@ -950,7 +854,7 @@ void *sb_1_init() memset(sb, 0, sizeof(sb_t)); opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB1); + sb_dsp_init(&sb->dsp, SB1, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); @@ -972,7 +876,7 @@ void *sb_15_init() memset(sb, 0, sizeof(sb_t)); opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB15); + sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); @@ -993,7 +897,7 @@ void *sb_mcv_init() memset(sb, 0, sizeof(sb_t)); opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB15); + sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, 0);//addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); @@ -1024,7 +928,7 @@ void *sb_2_init() memset(sb, 0, sizeof(sb_t)); opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB2); + sb_dsp_init(&sb->dsp, SB2, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); @@ -1061,7 +965,7 @@ void *sb_pro_v1_init() memset(sb, 0, sizeof(sb_t)); opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SBPRO); + sb_dsp_init(&sb->dsp, SBPRO, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); @@ -1091,7 +995,7 @@ void *sb_pro_v2_init() uint16_t addr = device_get_config_int("addr"); sb->opl_emu = device_get_config_int("opl_emu"); opl3_init(&sb->opl, sb->opl_emu); - sb_dsp_init(&sb->dsp, SBPRO2); + sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); @@ -1118,7 +1022,7 @@ void *sb_pro_mcv_init() sb->opl_emu = device_get_config_int("opl_emu"); opl3_init(&sb->opl, sb->opl_emu); - sb_dsp_init(&sb->dsp, SBPRO2); + sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); sb_ct1345_mixer_reset(sb); /* I/O handlers activated in sb_mcv_write */ sound_add_handler(sb_get_buffer_sbpro, sb); @@ -1139,7 +1043,7 @@ void *sb_16_init() uint16_t addr = device_get_config_int("addr"); sb->opl_emu = device_get_config_int("opl_emu"); opl3_init(&sb->opl, sb->opl_emu); - sb_dsp_init(&sb->dsp, SB16); + sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); // TODO: irq and dma options too? sb_ct1745_mixer_reset(sb); @@ -1148,7 +1052,7 @@ void *sb_16_init() io_sethandler(0x0388, 0x0004, 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); sound_add_handler(sb_get_buffer_sb16, sb); - mpu401_uart_init(&sb->mpu, 0x330); + mpu401_uart_init(&sb->mpu, 0x330, -1); return sb; @@ -1169,7 +1073,7 @@ void *sb_awe32_init() uint16_t emu_addr = device_get_config_int("emu_addr"); sb->opl_emu = device_get_config_int("opl_emu"); opl3_init(&sb->opl, sb->opl_emu); - sb_dsp_init(&sb->dsp, SB16 + 1); + sb_dsp_init(&sb->dsp, SB16 + 1, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, addr); // TODO: irq and dma options too? sb_ct1745_mixer_reset(sb); @@ -1178,7 +1082,7 @@ void *sb_awe32_init() io_sethandler(0x0388, 0x0004, 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); sound_add_handler(sb_get_buffer_emu8k, sb); - mpu401_uart_init(&sb->mpu, 0x330); + mpu401_uart_init(&sb->mpu, 0x330, -1); emu8k_init(&sb->emu8k, emu_addr, onboard_ram); return sb; diff --git a/src/sound_sb.h b/src/sound_sb.h index fb856c8..405bd39 100644 --- a/src/sound_sb.h +++ b/src/sound_sb.h @@ -1,3 +1,10 @@ +#ifndef SOUND_SB_H +#define SOUND_SB_H + +#include "sound_emu8k.h" +#include "sound_mpu401_uart.h" +#include "sound_sb_dsp.h" + extern device_t sb_1_device; extern device_t sb_15_device; extern device_t sb_mcv_device; @@ -7,3 +14,110 @@ extern device_t sb_pro_v2_device; extern device_t sb_pro_mcv_device; extern device_t sb_16_device; extern device_t sb_awe32_device; + +/* SB 2.0 CD version */ +typedef struct sb_ct1335_mixer_t +{ + int32_t master; + int32_t voice; + int32_t fm; + int32_t cd; + + uint8_t index; + uint8_t regs[256]; +} sb_ct1335_mixer_t; +/* SB PRO */ +typedef struct sb_ct1345_mixer_t +{ + int32_t master_l, master_r; + int32_t voice_l, voice_r; + int32_t fm_l, fm_r; + int32_t cd_l, cd_r; + int32_t line_l, line_r; + int32_t mic; + /*see sb_ct1745_mixer for values for input selector*/ + int32_t input_selector; + + int input_filter; + int in_filter_freq; + int output_filter; + + int stereo; + int stereo_isleft; + + uint8_t index; + uint8_t regs[256]; + +} sb_ct1345_mixer_t; +/* SB16 and AWE32 */ +typedef struct sb_ct1745_mixer_t +{ + int32_t master_l, master_r; + int32_t voice_l, voice_r; + int32_t fm_l, fm_r; + int32_t cd_l, cd_r; + int32_t line_l, line_r; + int32_t mic; + int32_t speaker; + + int bass_l, bass_r; + int treble_l, treble_r; + + int output_selector; + #define OUTPUT_MIC 1 + #define OUTPUT_CD_R 2 + #define OUTPUT_CD_L 4 + #define OUTPUT_LINE_R 8 + #define OUTPUT_LINE_L 16 + + int input_selector_left; + int input_selector_right; + #define INPUT_MIC 1 + #define INPUT_CD_R 2 + #define INPUT_CD_L 4 + #define INPUT_LINE_R 8 + #define INPUT_LINE_L 16 + #define INPUT_MIDI_R 32 + #define INPUT_MIDI_L 64 + + int mic_agc; + + int32_t input_gain_L; + int32_t input_gain_R; + int32_t output_gain_L; + int32_t output_gain_R; + + uint8_t index; + uint8_t regs[256]; +} sb_ct1745_mixer_t; + +typedef struct sb_t +{ + opl_t opl; + sb_dsp_t dsp; + union { + sb_ct1335_mixer_t mixer_sb2; + sb_ct1345_mixer_t mixer_sbpro; + sb_ct1745_mixer_t mixer_sb16; + }; + mpu401_uart_t mpu; + emu8k_t emu8k; + + int pos; + + uint8_t pos_regs[8]; + + int opl_emu; +} sb_t; + +// exported for clone cards +void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p); +void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p); +uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p); +void sb_ct1345_mixer_reset(sb_t* sb); + +void sb_close(void *p); +void sb_speed_changed(void *p); +void sb_add_status_info(char *s, int max_len, void *p); + +#endif /* SOUND_SB_H */ diff --git a/src/sound_sb_dsp.c b/src/sound_sb_dsp.c index 25de3ee..0cf391a 100644 --- a/src/sound_sb_dsp.c +++ b/src/sound_sb_dsp.c @@ -10,13 +10,16 @@ #include "ibm.h" +#include "device.h" #include "dma.h" #include "filters.h" #include "io.h" #include "pic.h" #include "sound.h" +#include "sound_azt2316a.h" #include "sound_sb_dsp.h" #include "timer.h" +#include "x86.h" /*The recording safety margin is intended for uneven "len" calls to the get_buffer mixer calls on sound_sb*/ #define SB_DSP_REC_SAFEFTY_MARGIN 4096 @@ -205,10 +208,18 @@ void sb_doreset(sb_dsp_t *dsp) int c; sb_dsp_reset(dsp); - - if (dsp->sb_type==SB16) sb_commands[8] = 1; - else sb_commands[8] = -1; - + + if (IS_AZTECH(dsp)) + { + sb_commands[8] = 1; + sb_commands[9] = 1; + } + else + { + if (dsp->sb_type==SB16) sb_commands[8] = 1; + else sb_commands[8] = -1; + } + for (c = 0; c < 256; c++) dsp->sb_asp_regs[c] = 0; dsp->sb_asp_regs[5] = 0x01; @@ -579,6 +590,20 @@ void sb_exec_command(sb_dsp_t *dsp) sb_add_data(dsp, ~dsp->sb_data[0]); break; case 0xE1: /*Get DSP version*/ + if (IS_AZTECH(dsp)) + { + if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11) + { + sb_add_data(dsp, 0x3); + sb_add_data(dsp, 0x1); + } + else if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) + { + sb_add_data(dsp, 0x2); + sb_add_data(dsp, 0x1); + } + break; + } sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8); sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff); break; @@ -617,6 +642,32 @@ void sb_exec_command(sb_dsp_t *dsp) case 0xFF: break; case 0x08: /*ASP get version*/ + if (IS_AZTECH(dsp)) + { + if ((dsp->sb_data[0] == 0x55 || dsp->sb_data[0] == 0x05) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11) + 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] == 0x55 || dsp->sb_data[0] == 0x05) && 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] == 0x08) + { + // EEPROM address to write followed by byte + if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE) + fatal("AZT EEPROM: out of bounds write to %02X\n", dsp->sb_data[1]); + dsp->azt_eeprom[dsp->sb_data[1]] = dsp->sb_data[2]; + break; + } + else if (dsp->sb_data[0] == 0x07) + { + // EEPROM address to read + if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE) + fatal("AZT EEPROM: out of bounds read to %02X\n", dsp->sb_data[1]); + sb_add_data(dsp, dsp->azt_eeprom[dsp->sb_data[1]]); + break; + } + else + pclog("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; + } if (dsp->sb_type < SB16) break; sb_add_data(dsp, 0x18); break; @@ -644,10 +695,26 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x04: case 0x05: break; -// default: -// fatal("Exec bad SB command %02X\n",sb_command); - - + case 0x09: /*AZTECH mode set*/ + if (dsp->sb_data[0] == 0x00) + { + pclog("AZT2316A: WSS MODE!\n"); + azt2316a_enable_wss(1, dsp->parent); + } + else if (dsp->sb_data[0] == 0x01) + { + pclog("AZT2316A: SB8PROV2 MODE!\n"); + azt2316a_enable_wss(0, dsp->parent); + } + else + pclog("AZT2316A: UNKNOWN MODE!\n"); // sequences 0x02->0xFF, 0x04->0xFF seen + break; + case 0x38: /*TODO: AZTECH MIDI-related? */ + break; + default: + fatal("Exec bad SB command %02X\n",dsp->sb_command); + + /*TODO: Some more data about the DSP registeres * http://the.earth.li/~tfm/oldpage/sb_dsp.html * http://www.synchrondata.com/pheaven/www/area19.htm @@ -680,7 +747,7 @@ void sb_write(uint16_t a, uint8_t v, void *priv) dsp->sbreset = v; return; case 0xC: /*Command/data write*/ - timer_set_delay_u64(&dsp->wb_timer, TIMER_USEC * 1); + timer_set_delay_u64(&dsp->wb_timer, TIMER_USEC * 1); if (dsp->asp_data_len) { // pclog("ASP data %i\n", dsp->asp_data_len); @@ -699,11 +766,27 @@ void sb_write(uint16_t a, uint8_t v, void *priv) dsp->sb_data_stat++; } else - dsp->sb_data[dsp->sb_data_stat++] = v; + { + dsp->sb_data[dsp->sb_data_stat++] = v; + if (IS_AZTECH(dsp)) + { + // 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) + sb_commands[dsp->sb_command] = 2; + } + } if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) { sb_exec_command(dsp); dsp->sb_data_stat = -1; + if (IS_AZTECH(dsp)) + { + // variable length commands + if (dsp->sb_command == 0x08) + sb_commands[dsp->sb_command] = 1; + } } break; } @@ -732,13 +815,31 @@ uint8_t sb_read(uint16_t a, void *priv) if (dsp->wb_full || (dsp->busy_count & 2)) { dsp->wb_full = timer_is_enabled(&dsp->wb_timer); - return 0xff; +// pclog("SB read 0x80\n"); + if (IS_AZTECH(dsp)) + return 0x80; + else + return 0xFF; } - return 0x7f; +// pclog("SB read 0x00\n"); + if (IS_AZTECH(dsp)) + return 0x00; + else + return 0x7F; case 0xE: /*Read data ready*/ picintc(1 << dsp->sb_irqnum); dsp->sb_irq8 = dsp->sb_irq16 = 0; - return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff; + // Only bit 7 is defined but aztech diagnostics fail if the others are set. Keep the original behavior to not interfere with what's already working. + if (IS_AZTECH(dsp)) + { +// pclog("SB read %02X\n",(dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80); + return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80; + } + else + { +// pclog("SB read %02X\n",(dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7F : 0xFF); + return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7F : 0xFF; + } case 0xF: /*16-bit ack*/ dsp->sb_irq16 = 0; if (!dsp->sb_irq8) picintc(1 << dsp->sb_irqnum); @@ -751,9 +852,11 @@ static void sb_wb_clear(void *p) { } -void sb_dsp_init(sb_dsp_t *dsp, int type) +void sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent) { dsp->sb_type = type; + dsp->sb_subtype = subtype; + dsp->parent = parent; // Default values. Use sb_dsp_setxxx() methods to change. dsp->sb_irqnum = 7; diff --git a/src/sound_sb_dsp.h b/src/sound_sb_dsp.h index cb14af5..33661c0 100644 --- a/src/sound_sb_dsp.h +++ b/src/sound_sb_dsp.h @@ -1,6 +1,20 @@ +#ifndef SOUND_SB_DSP_H +#define SOUND_SB_DSP_H + +/*Sound Blaster Clones, for quirks*/ +#define SB_SUBTYPE_DEFAULT 0 /*Handle as a Creative card*/ +#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*/ + +// 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 + typedef struct sb_dsp_t { int sb_type; + int sb_subtype; // which clone + void *parent; // "sb_t *" if default subtype, "azt2316a_t *" if aztech. int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; int sb_8_dmanum; @@ -67,9 +81,11 @@ typedef struct sb_dsp_t int16_t record_buffer[0xFFFF]; int16_t buffer[MAXSOUNDBUFLEN * 2]; int pos; + + uint8_t azt_eeprom[AZTECH_EEPROM_SIZE]; // the eeprom in the Aztech cards is attached to the DSP } sb_dsp_t; -void sb_dsp_init(sb_dsp_t *dsp, int type); +void sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent); void sb_dsp_close(sb_dsp_t *dsp); void sb_dsp_setirq(sb_dsp_t *dsp, int irq); @@ -86,3 +102,5 @@ void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo); void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp); void sb_dsp_update(sb_dsp_t *dsp); + +#endif /* SOUND_SB_DSP_H */ diff --git a/src/sound_wss.c b/src/sound_wss.c index 4129744..edbc272 100644 --- a/src/sound_wss.c +++ b/src/sound_wss.c @@ -84,7 +84,7 @@ void *wss_init() opl_emu = device_get_config_int("opl_emu"); opl3_init(&wss->opl, opl_emu); - ad1848_init(&wss->ad1848); + ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); ad1848_setirq(&wss->ad1848, 7); ad1848_setdma(&wss->ad1848, 3);