Finish DSP part of ESS
This commit is contained in:
@@ -143,6 +143,7 @@ typedef struct sb_dsp_t {
|
||||
uint8_t ess_regs[256]; /* ESS registers. */
|
||||
uint8_t ess_playback_mode;
|
||||
uint8_t ess_extended_mode;
|
||||
uint8_t ess_reload_len;
|
||||
|
||||
mpu_t *mpu;
|
||||
} sb_dsp_t;
|
||||
|
@@ -18,7 +18,7 @@ add_library(snd OBJECT sound.c snd_opl.c snd_opl_nuked.c snd_opl_ymfm.cpp snd_re
|
||||
snd_lpt_dss.c snd_ps1.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c
|
||||
snd_azt2316a.c snd_cms.c snd_cmi8x38.c snd_cs423x.c snd_gus.c snd_sb.c snd_sb_dsp.c
|
||||
snd_emu8k.c snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c
|
||||
snd_optimc.c esfmu/esfm.c esfmu/esfm_registers.c snd_opl_esfm.c)
|
||||
snd_optimc.c esfmu/esfm.c esfmu/esfm_registers.c snd_opl_esfm.c snd_ess.c)
|
||||
|
||||
if(OPENAL)
|
||||
if(VCPKG_TOOLCHAIN)
|
||||
|
258
src/sound/snd_ess.c
Normal file
258
src/sound/snd_ess.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Sound Blaster emulation.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* TheCollector1995, <mariogplayer@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2020 Sarah Walker.
|
||||
* Copyright 2016-2020 Miran Grca.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/filters.h>
|
||||
#include <86box/gameport.h>
|
||||
#include <86box/hdc.h>
|
||||
#include <86box/isapnp.h>
|
||||
#include <86box/hdc_ide.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/mca.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/midi.h>
|
||||
#include <86box/pic.h>
|
||||
#include <86box/rom.h>
|
||||
#include <86box/sound.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/snd_sb.h>
|
||||
#include <86box/plat_unused.h>
|
||||
|
||||
static const double sb_att_4dbstep_3bits[] = {
|
||||
164.0, 2067.0, 3276.0, 5193.0, 8230.0, 13045.0, 20675.0, 32767.0
|
||||
};
|
||||
|
||||
static const double sb_att_7dbstep_2bits[] = {
|
||||
164.0, 6537.0, 14637.0, 32767.0
|
||||
};
|
||||
|
||||
/* SB PRO */
|
||||
typedef struct ess_mixer_t {
|
||||
double master_l;
|
||||
double master_r;
|
||||
double voice_l;
|
||||
double voice_r;
|
||||
double fm_l;
|
||||
double fm_r;
|
||||
double cd_l;
|
||||
double cd_r;
|
||||
double line_l;
|
||||
double line_r;
|
||||
double 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];
|
||||
} ess_mixer_t;
|
||||
|
||||
typedef struct ess_t {
|
||||
uint8_t mixer_enabled;
|
||||
fm_drv_t opl;
|
||||
sb_dsp_t dsp;
|
||||
union {
|
||||
ess_mixer_t mixer_sbpro;
|
||||
};
|
||||
mpu_t *mpu;
|
||||
emu8k_t emu8k;
|
||||
void *gameport;
|
||||
|
||||
int pnp;
|
||||
|
||||
uint8_t pos_regs[8];
|
||||
uint8_t pnp_rom[512];
|
||||
|
||||
uint16_t opl_pnp_addr;
|
||||
uint16_t gameport_addr;
|
||||
|
||||
void *opl_mixer;
|
||||
void (*opl_mix)(void*, double*, double*);
|
||||
} ess_t;
|
||||
|
||||
static inline uint8_t expand16to32(const uint8_t t) {
|
||||
/* 4-bit -> 5-bit expansion.
|
||||
*
|
||||
* 0 -> 0
|
||||
* 1 -> 2
|
||||
* 2 -> 4
|
||||
* 3 -> 6
|
||||
* ....
|
||||
* 7 -> 14
|
||||
* 8 -> 17
|
||||
* 9 -> 19
|
||||
* 10 -> 21
|
||||
* 11 -> 23
|
||||
* ....
|
||||
* 15 -> 31 */
|
||||
return (t << 1) | (t >> 3);
|
||||
}
|
||||
|
||||
void
|
||||
ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
ess_t *ess = (ess_t *) priv;
|
||||
ess_mixer_t *mixer = &ess->mixer_sbpro;
|
||||
|
||||
if (!(addr & 1)) {
|
||||
mixer->index = val;
|
||||
mixer->regs[0x01] = val;
|
||||
} else {
|
||||
if (mixer->index == 0) {
|
||||
/* Reset */
|
||||
mixer->regs[0x0a] = mixer->regs[0x0c] = 0x00;
|
||||
mixer->regs[0x0e] = 0x00;
|
||||
/* Changed default from -11dB to 0dB */
|
||||
mixer->regs[0x04] = mixer->regs[0x22] = 0xee;
|
||||
mixer->regs[0x26] = mixer->regs[0x28] = 0xee;
|
||||
mixer->regs[0x2e] = 0x00;
|
||||
sb_dsp_set_stereo(&ess->dsp, mixer->regs[0x0e] & 2);
|
||||
} else {
|
||||
mixer->regs[mixer->index] = val;
|
||||
|
||||
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;
|
||||
|
||||
default:
|
||||
//sb_log("ess: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mixer->voice_l = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 5) & 0x7] / 32768.0;
|
||||
mixer->voice_r = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 1) & 0x7] / 32768.0;
|
||||
mixer->master_l = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 5) & 0x7] / 32768.0;
|
||||
mixer->master_r = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 1) & 0x7] / 32768.0;
|
||||
mixer->fm_l = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 5) & 0x7] / 32768.0;
|
||||
mixer->fm_r = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 1) & 0x7] / 32768.0;
|
||||
mixer->cd_l = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 5) & 0x7] / 32768.0;
|
||||
mixer->cd_r = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 1) & 0x7] / 32768.0;
|
||||
mixer->line_l = sb_att_4dbstep_3bits[(mixer->regs[0x2e] >> 5) & 0x7] / 32768.0;
|
||||
mixer->line_r = sb_att_4dbstep_3bits[(mixer->regs[0x2e] >> 1) & 0x7] / 32768.0;
|
||||
|
||||
mixer->mic = sb_att_7dbstep_2bits[(mixer->regs[0x0a] >> 1) & 0x3] / 32768.0;
|
||||
|
||||
mixer->output_filter = !(mixer->regs[0xe] & 0x20);
|
||||
mixer->input_filter = !(mixer->regs[0xc] & 0x20);
|
||||
mixer->in_filter_freq = ((mixer->regs[0xc] & 0x8) == 0) ? 3200 : 8800;
|
||||
mixer->stereo = mixer->regs[0xe] & 2;
|
||||
if (mixer->index == 0xe)
|
||||
sb_dsp_set_stereo(&ess->dsp, val & 2);
|
||||
|
||||
switch (mixer->regs[0xc] & 6) {
|
||||
case 2:
|
||||
mixer->input_selector = INPUT_CD_L | INPUT_CD_R;
|
||||
break;
|
||||
case 6:
|
||||
mixer->input_selector = INPUT_LINE_L | INPUT_LINE_R;
|
||||
break;
|
||||
default:
|
||||
mixer->input_selector = INPUT_MIC;
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO: pcspeaker volume? Or is it not worth? */
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ess_mixer_read(uint16_t addr, void *priv)
|
||||
{
|
||||
const ess_t *ess = (ess_t *) priv;
|
||||
const ess_mixer_t *mixer = &ess->mixer_sbpro;
|
||||
|
||||
if (!(addr & 1))
|
||||
return mixer->index;
|
||||
|
||||
switch (mixer->index) {
|
||||
case 0x00:
|
||||
case 0x04:
|
||||
case 0x0a:
|
||||
case 0x0c:
|
||||
case 0x0e:
|
||||
case 0x22:
|
||||
case 0x26:
|
||||
case 0x28:
|
||||
case 0x2e:
|
||||
case 0x02:
|
||||
case 0x06:
|
||||
case 0x30:
|
||||
case 0x32:
|
||||
case 0x36:
|
||||
case 0x38:
|
||||
return mixer->regs[mixer->index];
|
||||
|
||||
default:
|
||||
//sb_log("ess: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
void
|
||||
ess_mixer_reset(ess_t *ess)
|
||||
{
|
||||
ess_mixer_write(4, 0, ess);
|
||||
ess_mixer_write(5, 0, ess);
|
||||
}
|
@@ -6,6 +6,7 @@
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -418,30 +419,65 @@ sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len)
|
||||
memset(dsp->record_buffer, 0, sizeof(dsp->record_buffer));
|
||||
}
|
||||
|
||||
void
|
||||
sb_start_dma_ess(sb_dsp_t* dsp, int dma8, int autoinit, uint8_t format, int len)
|
||||
|
||||
static unsigned int sb_ess_get_dma_len(sb_dsp_t *dsp)
|
||||
{
|
||||
unsigned int r;
|
||||
|
||||
r = (unsigned int)ESSreg(0xA5) << 8U;
|
||||
r |= (unsigned int)ESSreg(0xA4);
|
||||
|
||||
/* the 16-bit counter is a "two's complement" of the DMA count because it counts UP to 0 and triggers IRQ on overflow */
|
||||
return 0x10000U-r;
|
||||
}
|
||||
|
||||
void
|
||||
sb_start_dma_ess(sb_dsp_t* dsp)
|
||||
{
|
||||
uint8_t real_format = 0;
|
||||
uint32_t len = !(ESSreg(0xB7) & 4) ? dsp->sb_8_length : dsp->sb_16_length;
|
||||
|
||||
if (!dsp->ess_reload_len) {
|
||||
len = sb_ess_get_dma_len(dsp);
|
||||
}
|
||||
|
||||
if (IS_ESS(dsp)) {
|
||||
dma_set_drq(dsp->sb_8_dmanum, 0);
|
||||
dma_set_drq(dsp->sb_16_8_dmanum, 0);
|
||||
}
|
||||
sb_start_dma(dsp, dma8, autoinit, format, len);
|
||||
real_format |= !!(ESSreg(0xB7) & 0x20) ? 0x10 : 0;
|
||||
real_format |= !!(ESSreg(0xB7) & 0x8) ? 0x20 : 0;
|
||||
if (!!(ESSreg(0xB8) & 8))
|
||||
sb_start_dma_i(dsp, !(ESSreg(0xB7) & 4), (ESSreg(0xB8) >> 2) & 1, real_format, sb_ess_get_dma_len(dsp));
|
||||
else
|
||||
sb_start_dma(dsp, !(ESSreg(0xB7) & 4), (ESSreg(0xB8) >> 2) & 1, real_format, sb_ess_get_dma_len(dsp));
|
||||
dsp->ess_playback_mode = 1;
|
||||
dma_set_drq(dsp->sb_8_dmanum, 1);
|
||||
dma_set_drq(dsp->sb_16_8_dmanum, 1);
|
||||
}
|
||||
|
||||
void
|
||||
sb_start_dma_ess_i(sb_dsp_t* dsp, int dma8, int autoinit, uint8_t format, int len)
|
||||
sb_stop_dma_ess(sb_dsp_t* dsp)
|
||||
{
|
||||
if (IS_ESS(dsp)) {
|
||||
dma_set_drq(dsp->sb_8_dmanum, 0);
|
||||
dma_set_drq(dsp->sb_16_8_dmanum, 0);
|
||||
dsp->sb_8_enable = dsp->sb_16_enable = 0;
|
||||
dma_set_drq(dsp->sb_16_8_dmanum, 0);
|
||||
dma_set_drq(dsp->sb_8_dmanum, 0);
|
||||
}
|
||||
|
||||
static void sb_ess_update_dma_status(sb_dsp_t* dsp)
|
||||
{
|
||||
bool dma_en = (ESSreg(0xB8) & 1)?true:false;
|
||||
|
||||
// if the DRQ is disabled, do not start
|
||||
if (!(ESSreg(0xB2) & 0x40))
|
||||
dma_en = false;
|
||||
|
||||
if (dma_en) {
|
||||
if (!dsp->sb_8_enable && !dsp->sb_16_enable) sb_start_dma_ess(dsp);
|
||||
}
|
||||
else {
|
||||
if (dsp->sb_8_enable || dsp->sb_16_enable) sb_stop_dma_ess(dsp);
|
||||
}
|
||||
sb_start_dma_i(dsp, dma8, autoinit, format, len);
|
||||
dsp->ess_playback_mode = 1;
|
||||
dma_set_drq(dsp->sb_8_dmanum, 1);
|
||||
dma_set_drq(dsp->sb_16_8_dmanum, 1);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -598,17 +634,6 @@ static void sb_ess_update_filter_freq(sb_dsp_t *dsp)
|
||||
ESSreg(0xA2) = 256 - (7160000 / (freq * 82));
|
||||
}
|
||||
|
||||
static unsigned int sb_ess_get_dma_len(sb_dsp_t *dsp)
|
||||
{
|
||||
unsigned int r;
|
||||
|
||||
r = (unsigned int)ESSreg(0xA5) << 8U;
|
||||
r |= (unsigned int)ESSreg(0xA4);
|
||||
|
||||
/* the 16-bit counter is a "two's complement" of the DMA count because it counts UP to 0 and triggers IRQ on overflow */
|
||||
return 0x10000U-r;
|
||||
}
|
||||
|
||||
static uint8_t sb_ess_read_reg(sb_dsp_t *dsp, uint8_t reg)
|
||||
{
|
||||
switch (reg) {
|
||||
@@ -619,6 +644,120 @@ static uint8_t sb_ess_read_reg(sb_dsp_t *dsp, uint8_t reg)
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
static void sb_ess_write_reg(sb_dsp_t *dsp, uint8_t reg, uint8_t data)
|
||||
{
|
||||
uint8_t chg = 0x00;
|
||||
sb_dsp_log("ESS register write reg=%02xh val=%02xh\n",reg,data);
|
||||
|
||||
switch (reg) {
|
||||
case 0xA1: /* Extended Mode Sample Rate Generator */
|
||||
{
|
||||
ESSreg(reg) = data;
|
||||
if (data & 0x80)
|
||||
dsp->sb_freq = 795500UL / (256ul - data);
|
||||
else
|
||||
dsp->sb_freq = 397700UL / (128ul - data);
|
||||
|
||||
if (dsp->sb_16_enable || dsp->sb_8_enable) {
|
||||
sb_stop_dma_ess(dsp);
|
||||
sb_start_dma_ess(dsp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0xA2: /* Filter divider (effectively, a hardware lowpass filter under S/W control) */
|
||||
ESSreg(reg) = data;
|
||||
break;
|
||||
|
||||
case 0xA4: /* DMA Transfer Count Reload (low) */
|
||||
case 0xA5: /* DMA Transfer Count Reload (high) */
|
||||
ESSreg(reg) = data;
|
||||
if (dsp->sb_16_length == 0 || dsp->sb_8_length == 0)
|
||||
dsp->ess_reload_len = 1;
|
||||
break;
|
||||
|
||||
case 0xA8: /* Analog Control */
|
||||
/* bits 7:5 0 Reserved. Always write 0
|
||||
* bit 4 1 Reserved. Always write 1
|
||||
* bit 3 Record monitor 1=Enable record monitor
|
||||
* enable
|
||||
* bit 2 0 Reserved. Always write 0
|
||||
* bits 1:0 Stereo/mono select 00=Reserved
|
||||
* 01=Stereo
|
||||
* 10=Mono
|
||||
* 11=Reserved */
|
||||
chg = ESSreg(reg) ^ data;
|
||||
ESSreg(reg) = data;
|
||||
if (chg & 0x3) {
|
||||
if (dsp->sb_16_enable || dsp->sb_8_enable) {
|
||||
sb_stop_dma_ess(dsp);
|
||||
sb_start_dma_ess(dsp);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB1: /* Legacy Audio Interrupt Control */
|
||||
case 0xB2: /* DRQ Control */
|
||||
chg = ESSreg(reg) ^ data;
|
||||
ESSreg(reg) = (ESSreg(reg) & 0x0F) + (data & 0xF0); // lower 4 bits not writeable
|
||||
if (chg & 0x40) sb_ess_update_dma_status(dsp);
|
||||
break;
|
||||
case 0xB5: /* DAC Direct Access Holding (low) */
|
||||
case 0xB6: /* DAC Direct Access Holding (high) */
|
||||
ESSreg(reg) = data;
|
||||
break;
|
||||
|
||||
case 0xB7: /* Audio 1 Control 1 */
|
||||
/* bit 7 Enable FIFO to/from codec
|
||||
* bit 6 Opposite from bit 3 Must be set opposite to bit 3
|
||||
* bit 5 FIFO signed mode 1=Data is signed twos-complement 0=Data is unsigned
|
||||
* bit 4 Reserved Always write 1
|
||||
* bit 3 FIFO stereo mode 1=Data is stereo
|
||||
* bit 2 FIFO 16-bit mode 1=Data is 16-bit
|
||||
* bit 1 Reserved Always write 0
|
||||
* bit 0 Generate load signal */
|
||||
chg = ESSreg(reg) ^ data;
|
||||
ESSreg(reg) = data;
|
||||
if (chg & 0x0C) {
|
||||
if (dsp->sb_16_enable || dsp->sb_8_enable) {
|
||||
sb_stop_dma_ess(dsp);
|
||||
sb_start_dma_ess(dsp);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB8: /* Audio 1 Control 2 */
|
||||
/* bits 7:4 reserved
|
||||
* bit 3 CODEC mode 1=first DMA converter in ADC mode
|
||||
* 0=first DMA converter in DAC mode
|
||||
* bit 2 DMA mode 1=auto-initialize mode
|
||||
* 0=normal DMA mode
|
||||
* bit 1 DMA read enable 1=first DMA is read (for ADC)
|
||||
* 0=first DMA is write (for DAC)
|
||||
* bit 0 DMA xfer enable 1=DMA is allowed to proceed */
|
||||
data &= 0xF;
|
||||
chg = ESSreg(reg) ^ data;
|
||||
ESSreg(reg) = data;
|
||||
|
||||
if (chg & 1)
|
||||
dsp->ess_reload_len = 1;
|
||||
|
||||
if (chg & 0xB) {
|
||||
if (chg & 0xA) sb_stop_dma_ess(dsp); /* changing capture/playback direction? stop DMA to reinit */
|
||||
sb_ess_update_dma_status(dsp);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB9: /* Audio 1 Transfer Type */
|
||||
case 0xBA: /* Left Channel ADC Offset Adjust */
|
||||
case 0xBB: /* Right Channel ADC Offset Adjust */
|
||||
ESSreg(reg) = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sb_exec_command(sb_dsp_t *dsp)
|
||||
{
|
||||
@@ -632,11 +771,17 @@ sb_exec_command(sb_dsp_t *dsp)
|
||||
if (dsp->sb_type >= SB16)
|
||||
dsp->sb_8051_ram[0x20] = dsp->sb_command;
|
||||
|
||||
if (IS_ESS(dsp)) {
|
||||
if (dsp->sb_command == 0xC6 || dsp->sb_command == 0xC7){
|
||||
if (IS_ESS(dsp) && dsp->sb_command >= 0xA0 && dsp->sb_command <= 0xCF) {
|
||||
if (dsp->sb_command == 0xC6 || dsp->sb_command == 0xC7) {
|
||||
dsp->ess_extended_mode = !!(dsp->sb_command == 0xC6);
|
||||
return;
|
||||
}
|
||||
if (dsp->sb_command == 0xC0) {
|
||||
sb_add_data(dsp, sb_ess_read_reg(dsp, dsp->sb_data[0]));
|
||||
} else if (dsp->sb_command < 0xC0 && dsp->ess_extended_mode) {
|
||||
sb_ess_write_reg(dsp, dsp->sb_command, dsp->sb_data[0]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dsp->sb_command) {
|
||||
@@ -1062,12 +1207,29 @@ sb_exec_command(sb_dsp_t *dsp)
|
||||
while (sb16_copyright[c])
|
||||
sb_add_data(dsp, sb16_copyright[c++]);
|
||||
sb_add_data(dsp, 0);
|
||||
} else if (IS_ESS(dsp)) {
|
||||
sb_add_data(dsp, 0);
|
||||
}
|
||||
break;
|
||||
case 0xE4: /* Write test register */
|
||||
dsp->sb_test = dsp->sb_data[0];
|
||||
break;
|
||||
case 0xE7: /* ???? */
|
||||
case 0xE7: /* ???? */ /* ESS detect/read config on ESS cards */
|
||||
if (IS_ESS(dsp)) {
|
||||
switch (dsp->sb_subtype) {
|
||||
default:
|
||||
break;
|
||||
case SB_SUBTYPE_ESS_ES688:
|
||||
sb_add_data(dsp, 0x68);
|
||||
sb_add_data(dsp, 0x80 | 0x04);
|
||||
break;
|
||||
case SB_SUBTYPE_ESS_ES1688:
|
||||
// Determined via Windows driver debugging.
|
||||
sb_add_data(dsp, 0x68);
|
||||
sb_add_data(dsp, 0x80 | 0x09);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xE8: /* Read test register */
|
||||
sb_add_data(dsp, dsp->sb_test);
|
||||
@@ -1170,6 +1332,13 @@ sb_write(uint16_t a, uint8_t v, void *priv)
|
||||
else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x07)
|
||||
sb_commands[dsp->sb_command] = 2;
|
||||
}
|
||||
if (IS_ESS(dsp) && dsp->sb_command >= 0xA0 && dsp->sb_command <= 0xCF) {
|
||||
if (dsp->sb_command <= 0xC0) {
|
||||
sb_commands[dsp->sb_command] = 1;
|
||||
} else {
|
||||
sb_commands[dsp->sb_command] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) {
|
||||
sb_exec_command(dsp);
|
||||
|
Reference in New Issue
Block a user