diff --git a/src/include/86box/snd_ad1848.h b/src/include/86box/snd_ad1848.h index a25e46951..d1f4a4499 100644 --- a/src/include/86box/snd_ad1848.h +++ b/src/include/86box/snd_ad1848.h @@ -1,45 +1,65 @@ +/* + * 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. + * + * Definitions for AD1848 / CS4248 / CS4231 (Windows Sound System) codec emulation. + * + * + * + * Authors: Sarah Walker, + * TheCollector1995, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2018-2020 TheCollector1995. + */ + #define AD1848_TYPE_DEFAULT 0 #define AD1848_TYPE_CS4248 1 #define AD1848_TYPE_CS4231 2 #define AD1848_TYPE_CS4236 3 -typedef struct ad1848_t -{ - int index; - uint8_t regs[32]; /* 16 original + 16 CS4231A extensions */ - uint8_t status; - - int trd; - int mce; - - int count; - - int16_t out_l, out_r; - double cd_vol_l, cd_vol_r; +typedef struct { + int index; + uint8_t regs[32]; /* 16 original + 16 CS4231A extensions */ + uint8_t status; + + int trd; + int mce; + + int count; + + int16_t out_l, out_r; - int enable; + double cd_vol_l, cd_vol_r; - int irq, dma; - - int freq; - - pc_timer_t timer_count; - uint64_t timer_latch; + int enable; - int16_t buffer[SOUNDBUFLEN * 2]; - int pos; - - int type; + int irq, dma; + + int freq; + + pc_timer_t timer_count; + uint64_t timer_latch; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; + + int type; } ad1848_t; -void ad1848_setirq(ad1848_t *ad1848, int irq); -void ad1848_setdma(ad1848_t *ad1848, int dma); -uint8_t ad1848_read(uint16_t addr, void *p); -void ad1848_write(uint16_t addr, uint8_t val, void *p); +extern void ad1848_setirq(ad1848_t *ad1848, int irq); +extern void ad1848_setdma(ad1848_t *ad1848, int dma); -void ad1848_update(ad1848_t *ad1848); -void ad1848_speed_changed(ad1848_t *ad1848); +extern uint8_t ad1848_read(uint16_t addr, void *p); +extern void ad1848_write(uint16_t addr, uint8_t val, void *p); -void ad1848_init(ad1848_t *ad1848, int type); +extern void ad1848_update(ad1848_t *ad1848); +extern void ad1848_speed_changed(ad1848_t *ad1848); + +extern void ad1848_init(ad1848_t *ad1848, int type); diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index c45d69063..51c0423bd 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -1,6 +1,21 @@ /* - AD1848 / CS4248 / CS4231 CODEC emulation (Windows Sound System compatible)*/ - + * 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. + * + * AD1848 / CS4248 / CS4231 (Windows Sound System) codec emulation. + * + * + * + * Authors: Sarah Walker, + * TheCollector1995, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2018-2020 TheCollector1995. + */ #include #include #include @@ -13,302 +28,317 @@ #include <86box/sound.h> #include <86box/snd_ad1848.h> + #define CS4231 0x80 #define CS4236 0x03 -static int ad1848_vols_6bits[64]; -static double ad1848_vols_5bits_aux_gain[32]; + +static int ad1848_vols_6bits[64]; +static double ad1848_vols_5bits_aux_gain[32]; -void ad1848_setirq(ad1848_t *ad1848, int irq) +void +ad1848_setirq(ad1848_t *ad1848, int irq) { - ad1848->irq = irq; + ad1848->irq = irq; } -void ad1848_setdma(ad1848_t *ad1848, int dma) + +void +ad1848_setdma(ad1848_t *ad1848, int dma) { - ad1848->dma = dma; + ad1848->dma = dma; } -uint8_t ad1848_read(uint16_t addr, void *p) + +uint8_t +ad1848_read(uint16_t addr, void *priv) { - ad1848_t *ad1848 = (ad1848_t *)p; - uint8_t temp = 0xff; - switch (addr & 3) - { - case 0: /*Index*/ - temp = ad1848->index | ad1848->trd | ad1848->mce; - break; - case 1: - temp = ad1848->regs[ad1848->index]; - if (ad1848->index == 0x0b) { - temp ^= 0x20; - ad1848->regs[ad1848->index] = temp; + ad1848_t *ad1848 = (ad1848_t *) priv; + uint8_t ret = 0xff; + + switch (addr & 3) { + case 0: /*Index*/ + ret = ad1848->index | ad1848->trd | ad1848->mce; + break; + + case 1: + ret = ad1848->regs[ad1848->index]; + if (ad1848->index == 0x0b) { + ret ^= 0x20; + ad1848->regs[ad1848->index] = ret; } - break; - case 2: - temp = ad1848->status; - break; - } - return temp; + break; + + case 2: + ret = ad1848->status; + break; + } + + return ret; } -void ad1848_write(uint16_t addr, uint8_t val, void *p) + +void +ad1848_write(uint16_t addr, uint8_t val, void *priv) { - ad1848_t *ad1848 = (ad1848_t *)p; - double freq; - switch (addr & 3) - { - case 0: /*Index*/ - 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; - case 1: - switch (ad1848->index) - { - case 8: - freq = (val & 1) ? 16934400LL : 24576000LL; - switch ((val >> 1) & 7) - { - case 0: freq /= 3072; break; - case 1: freq /= 1536; break; - case 2: freq /= 896; break; - case 3: freq /= 768; break; - case 4: freq /= 448; break; - case 5: freq /= 384; break; - case 6: freq /= 512; break; - case 7: freq /= 2560; break; - } - ad1848->freq = freq; - ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); - break; - - case 9: - if (!ad1848->enable && (val & 0x41) == 0x01) { - if (ad1848->timer_latch) - timer_set_delay_u64(&ad1848->timer_count, ad1848->timer_latch); - else - timer_set_delay_u64(&ad1848->timer_count, TIMER_USEC); - } - ad1848->enable = ((val & 0x41) == 0x01); - if (!ad1848->enable) { - timer_disable(&ad1848->timer_count); - ad1848->out_l = ad1848->out_r = 0; - } - break; - - - case 11: - break; - - case 12: - if (ad1848->type != AD1848_TYPE_DEFAULT) - ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; - return; - - case 14: - ad1848->count = ad1848->regs[15] | (val << 8); - break; + ad1848_t *ad1848 = (ad1848_t *) priv; + double freq; + switch (addr & 3) { + case 0: /* Index */ + 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; - case 24: - if (! (val & 0x70)) - ad1848->status &= 0xfe; - break; - - case 25: + case 1: + switch (ad1848->index) { + case 8: + freq = (val & 1) ? 16934400LL : 24576000LL; + switch ((val >> 1) & 7) { + case 0: freq /= 3072; break; + case 1: freq /= 1536; break; + case 2: freq /= 896; break; + case 3: freq /= 768; break; + case 4: freq /= 448; break; + case 5: freq /= 384; break; + case 6: freq /= 512; break; + case 7: freq /= 2560; break; + } + ad1848->freq = freq; + ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + break; + + case 9: + if (!ad1848->enable && (val & 0x41) == 0x01) { + if (ad1848->timer_latch) + timer_set_delay_u64(&ad1848->timer_count, ad1848->timer_latch); + else + timer_set_delay_u64(&ad1848->timer_count, TIMER_USEC); + } + ad1848->enable = ((val & 0x41) == 0x01); + if (!ad1848->enable) { + timer_disable(&ad1848->timer_count); + ad1848->out_l = ad1848->out_r = 0; + } break; - } - ad1848->regs[ad1848->index] = val; - if (ad1848->type == AD1848_TYPE_CS4231) { /* TODO: configure CD volume for CS4248/AD1848 too */ - if (ad1848->regs[0x12] & 0x80) - ad1848->cd_vol_l = 0; - else - ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f]; - if (ad1848->regs[0x13] & 0x80) - ad1848->cd_vol_r = 0; - else - ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f]; - } - break; - case 2: - ad1848->status &= 0xfe; - break; - } + case 11: + break; + + case 12: + if (ad1848->type != AD1848_TYPE_DEFAULT) + ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; + return; + + case 14: + ad1848->count = ad1848->regs[15] | (val << 8); + break; + + case 24: + if (!(val & 0x70)) + ad1848->status &= 0xfe; + break; + + case 25: + break; + } + ad1848->regs[ad1848->index] = val; + + if (ad1848->type == AD1848_TYPE_CS4231) { /* TODO: configure CD volume for CS4248/AD1848 too */ + if (ad1848->regs[0x12] & 0x80) + ad1848->cd_vol_l = 0; + else + ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f]; + if (ad1848->regs[0x13] & 0x80) + ad1848->cd_vol_r = 0; + else + ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f]; + } + break; + + case 2: + ad1848->status &= 0xfe; + break; + } } -void ad1848_speed_changed(ad1848_t *ad1848) + +void +ad1848_speed_changed(ad1848_t *ad1848) { - ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + ad1848->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1848->freq)); } -void ad1848_update(ad1848_t *ad1848) + +void +ad1848_update(ad1848_t *ad1848) { - for (; ad1848->pos < sound_pos_global; ad1848->pos++) - { - ad1848->buffer[ad1848->pos*2] = ad1848->out_l; - ad1848->buffer[ad1848->pos*2 + 1] = ad1848->out_r; - } + for (; ad1848->pos < sound_pos_global; ad1848->pos++) { + ad1848->buffer[ad1848->pos*2] = ad1848->out_l; + ad1848->buffer[ad1848->pos*2 + 1] = ad1848->out_r; + } } -static void ad1848_poll(void *p) + +static void +ad1848_poll(void *priv) { - ad1848_t *ad1848 = (ad1848_t *)p; - - if (ad1848->timer_latch) - timer_advance_u64(&ad1848->timer_count, ad1848->timer_latch); - else - timer_advance_u64(&ad1848->timer_count, TIMER_USEC * 1000); + ad1848_t *ad1848 = (ad1848_t *) priv; - ad1848_update(ad1848); - - if (ad1848->enable) - { - int32_t temp; - - switch (ad1848->regs[8] & 0x70) - { - case 0x00: /*Mono, 8-bit PCM*/ - ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - break; - case 0x10: /*Stereo, 8-bit PCM*/ - ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; - break; - - case 0x40: /*Mono, 16-bit PCM*/ - temp = dma_channel_read(ad1848->dma); - ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; - break; - case 0x50: /*Stereo, 16-bit PCM*/ - temp = dma_channel_read(ad1848->dma); - ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; - temp = dma_channel_read(ad1848->dma); - ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; - break; - } + if (ad1848->timer_latch) + timer_advance_u64(&ad1848->timer_count, ad1848->timer_latch); + else + timer_advance_u64(&ad1848->timer_count, TIMER_USEC * 1000); - if (ad1848->regs[6] & 0x80) - ad1848->out_l = 0; - else - ad1848->out_l = (ad1848->out_l * ad1848_vols_6bits[ad1848->regs[6] & 0x3f]) >> 16; + ad1848_update(ad1848); - if (ad1848->regs[7] & 0x80) - ad1848->out_r = 0; - else - ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16; - - if (ad1848->count < 0) - { - ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); - if (!(ad1848->status & 0x01)) - { - ad1848->status |= 0x01; - if (ad1848->regs[10] & 2) - picint(1 << ad1848->irq); - } - } - - ad1848->count--; - } - else - { - ad1848->out_l = ad1848->out_r = 0; - ad1848->cd_vol_l = ad1848->cd_vol_r = 0; - } -} - -static void ad1848_filter_cd_audio(int channel, double *buffer, void *p) -{ - ad1848_t *ad1848 = (ad1848_t *)p; - double c; - double volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l; - - c = ((*buffer) * volume) / 65536.0; - *buffer = c; -} - -void ad1848_init(ad1848_t *ad1848, int type) -{ - int c; - double attenuation; - - ad1848->status = 0xcc; - ad1848->index = ad1848->trd = 0; - ad1848->mce = 0x40; - - ad1848->regs[0] = ad1848->regs[1] = 0; - ad1848->regs[2] = ad1848->regs[3] = 0x80; /* Line-in */ - ad1848->regs[4] = ad1848->regs[5] = 0x80; - ad1848->regs[6] = ad1848->regs[7] = 0x80; /* Left/right Output */ - ad1848->regs[8] = 0; - ad1848->regs[9] = 0x08; - ad1848->regs[10] = ad1848->regs[11] = 0; - if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231) || (type == AD1848_TYPE_CS4236)) - ad1848->regs[12] = 0x8a; - else - ad1848->regs[12] = 0xa; - ad1848->regs[13] = 0; - ad1848->regs[14] = ad1848->regs[15] = 0; - - if (type == AD1848_TYPE_CS4231) { - ad1848->regs[16] = ad1848->regs[17] = 0; - ad1848->regs[18] = ad1848->regs[19] = 0x88; - ad1848->regs[22] = 0x80; - ad1848->regs[24] = 0; - ad1848->regs[25] = CS4231; - ad1848->regs[26] = 0x80; - ad1848->regs[29] = 0x80; - } else if (type == AD1848_TYPE_CS4236) { - ad1848->regs[16] = ad1848->regs[17] = 0; - ad1848->regs[18] = ad1848->regs[19] = 0; - ad1848->regs[20] = ad1848->regs[21] = 0; - ad1848->regs[22] = ad1848->regs[23] = 0; - ad1848->regs[24] = 0; - ad1848->regs[25] = CS4236; - ad1848->regs[26] = 0xa0; - ad1848->regs[27] = ad1848->regs[29] = 0; - ad1848->regs[30] = ad1848->regs[31] = 0; - } + if (ad1848->enable) { + int32_t temp; - ad1848->out_l = 0; - ad1848->out_r = 0; - - for (c = 0; c < 64; c++) { - attenuation = 0.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; - if (c & 0x20) attenuation -= 48.0; - - attenuation = pow(10, attenuation / 10); - - ad1848_vols_6bits[c] = (int)(attenuation * 65536); - } - - 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] = (attenuation * 65536); - } + switch (ad1848->regs[8] & 0x70) { + case 0x00: /*Mono, 8-bit PCM*/ + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + case 0x10: /*Stereo, 8-bit PCM*/ + ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; - ad1848->type = type; - - timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); + case 0x40: /*Mono, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + case 0x50: /*Stereo, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + } - if (ad1848->type != AD1848_TYPE_DEFAULT && ad1848->type != AD1848_TYPE_CS4248) - sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848); + if (ad1848->regs[6] & 0x80) + ad1848->out_l = 0; + else + 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_6bits[ad1848->regs[7] & 0x3f]) >> 16; + + if (ad1848->count < 0) + { + ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); + if (!(ad1848->status & 0x01)) + { + ad1848->status |= 0x01; + if (ad1848->regs[10] & 2) + picint(1 << ad1848->irq); + } + } + + ad1848->count--; + } else { + ad1848->out_l = ad1848->out_r = 0; + ad1848->cd_vol_l = ad1848->cd_vol_r = 0; + } +} + + +static void +ad1848_filter_cd_audio(int channel, double *buffer, void *priv) +{ + ad1848_t *ad1848 = (ad1848_t *) priv; + double c; + double volume = channel ? ad1848->cd_vol_r : ad1848->cd_vol_l; + + c = ((*buffer) * volume) / 65536.0; + *buffer = c; +} + + +void +ad1848_init(ad1848_t *ad1848, int type) +{ + int c; + double attenuation; + + ad1848->status = 0xcc; + ad1848->index = ad1848->trd = 0; + ad1848->mce = 0x40; + + ad1848->regs[0] = ad1848->regs[1] = 0; + ad1848->regs[2] = ad1848->regs[3] = 0x80; /* Line-in */ + ad1848->regs[4] = ad1848->regs[5] = 0x80; + ad1848->regs[6] = ad1848->regs[7] = 0x80; /* Left/right Output */ + ad1848->regs[8] = 0; + ad1848->regs[9] = 0x08; + ad1848->regs[10] = ad1848->regs[11] = 0; + if ((type == AD1848_TYPE_CS4248) || (type == AD1848_TYPE_CS4231) || (type == AD1848_TYPE_CS4236)) + ad1848->regs[12] = 0x8a; + else + ad1848->regs[12] = 0xa; + ad1848->regs[13] = 0; + ad1848->regs[14] = ad1848->regs[15] = 0; + + if (type == AD1848_TYPE_CS4231) { + ad1848->regs[16] = ad1848->regs[17] = 0; + ad1848->regs[18] = ad1848->regs[19] = 0x88; + ad1848->regs[22] = 0x80; + ad1848->regs[24] = 0; + ad1848->regs[25] = CS4231; + ad1848->regs[26] = 0x80; + ad1848->regs[29] = 0x80; + } else if (type == AD1848_TYPE_CS4236) { + ad1848->regs[16] = ad1848->regs[17] = 0; + ad1848->regs[18] = ad1848->regs[19] = 0; + ad1848->regs[20] = ad1848->regs[21] = 0; + ad1848->regs[22] = ad1848->regs[23] = 0; + ad1848->regs[24] = 0; + ad1848->regs[25] = CS4236; + ad1848->regs[26] = 0xa0; + ad1848->regs[27] = ad1848->regs[29] = 0; + ad1848->regs[30] = ad1848->regs[31] = 0; + } + + ad1848->out_l = 0; + ad1848->out_r = 0; + + for (c = 0; c < 64; c++) { + attenuation = 0.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; + if (c & 0x20) attenuation -= 48.0; + + attenuation = pow(10, attenuation / 10); + + ad1848_vols_6bits[c] = (int)(attenuation * 65536); + } + + 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] = (attenuation * 65536); + } + + ad1848->type = type; + + timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); + + if (ad1848->type != AD1848_TYPE_DEFAULT && ad1848->type != AD1848_TYPE_CS4248) + sound_set_cd_audio_filter(ad1848_filter_cd_audio, ad1848); } diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index f7f813098..d77b781ea 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -34,217 +34,231 @@ #include <86box/snd_opl.h> -/*530, 11, 3 - 530=23*/ -/*530, 11, 1 - 530=22*/ -/*530, 11, 0 - 530=21*/ -/*530, 10, 1 - 530=1a*/ -/*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*/ +/* 530, 11, 3 - 530=23 + * 530, 11, 1 - 530=22 + * 530, 11, 0 - 530=21 + * 530, 10, 1 - 530=1a + * 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 wss_dma[4] = {0, 0, 1, 3}; -static int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /*W95 only uses 7-9, others may be wrong*/ +static const int wss_dma[4] = {0, 0, 1, 3}; +static const int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /* W95 only uses 7-9, others may be wrong */ -typedef struct wss_t -{ - uint8_t config; - ad1848_t ad1848; - opl_t opl; +typedef struct wss_t { + uint8_t config; - int opl_enabled; - uint8_t pos_regs[8]; + ad1848_t ad1848; + opl_t opl; + + int opl_enabled; + uint8_t pos_regs[8]; } wss_t; -uint8_t wss_read(uint16_t addr, void *p) -{ - wss_t *wss = (wss_t *)p; - uint8_t temp; - temp = 4 | (wss->config & 0x40); - return temp; + +uint8_t +wss_read(uint16_t addr, void *priv) { + wss_t *wss = (wss_t *) priv; + return 4 | (wss->config & 0x40); } -void wss_write(uint16_t addr, uint8_t val, void *p) -{ - wss_t *wss = (wss_t *)p; - wss->config = val; - ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); - ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); +void +wss_write(uint16_t addr, uint8_t val, void *priv) +{ + wss_t *wss = (wss_t *) priv; + + wss->config = val; + ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); + ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); } -static void wss_get_buffer(int32_t *buffer, int len, void *p) + +static void +wss_get_buffer(int32_t *buffer, int len, void *priv) { - wss_t *wss = (wss_t *)p; - int c; + wss_t *wss = (wss_t *) priv; + int c; - opl3_update(&wss->opl); - ad1848_update(&wss->ad1848); - for (c = 0; c < len * 2; c++) { - buffer[c] += wss->opl.buffer[c]; - buffer[c] += (wss->ad1848.buffer[c] / 2); - } + opl3_update(&wss->opl); + ad1848_update(&wss->ad1848); + for (c = 0; c < len * 2; c++) { + buffer[c] += wss->opl.buffer[c]; + buffer[c] += (wss->ad1848.buffer[c] / 2); + } - wss->opl.pos = 0; - wss->ad1848.pos = 0; + wss->opl.pos = 0; + wss->ad1848.pos = 0; } -void *wss_init(const device_t *info) + +void * +wss_init(const device_t *info) { - wss_t *wss = malloc(sizeof(wss_t)); - memset(wss, 0, sizeof(wss_t)); + wss_t *wss = malloc(sizeof(wss_t)); + memset(wss, 0, sizeof(wss_t)); - uint16_t addr = device_get_config_hex16("base"); - wss->opl_enabled = device_get_config_int("opl"); + uint16_t addr = device_get_config_hex16("base"); + wss->opl_enabled = device_get_config_int("opl"); - if (wss->opl_enabled) - opl3_init(&wss->opl); - - ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); + if (wss->opl_enabled) + opl3_init(&wss->opl); - ad1848_setirq(&wss->ad1848, 7); - ad1848_setdma(&wss->ad1848, 3); + ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); - if (wss->opl_enabled) + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); + + if (wss->opl_enabled) + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + + io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + + sound_add_handler(wss_get_buffer, wss); + + return wss; +} + + +static uint8_t +ncr_audio_mca_read(int port, void *priv) +{ + wss_t *wss = (wss_t *) priv; + return wss->pos_regs[port & 7]; +} + + +static void +ncr_audio_mca_write(int port, uint8_t val, void *priv) +{ + wss_t *wss = (wss_t *) priv; + uint16_t ports[4] = {0x530, 0xE80, 0xF40, 0x604}; + uint16_t addr; + + if (port < 0x102) + return; + + wss->opl_enabled = (wss->pos_regs[2] & 0x20) ? 1 : 0; + addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + + io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + io_removehandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_removehandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + + wss->pos_regs[port & 7] = val; + + if (wss->pos_regs[2] & 1) { + addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + + if (wss->opl_enabled) io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - + io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); - - sound_add_handler(wss_get_buffer, wss); - - return wss; + } } -static uint8_t ncr_audio_mca_read(int port, void *p) + +static uint8_t +ncr_audio_mca_feedb(void *priv) { - wss_t *wss = (wss_t *)p; - - return wss->pos_regs[port & 7]; + wss_t *wss = (wss_t *) priv; + return (wss->pos_regs[2] & 1); } -static void ncr_audio_mca_write(int port, uint8_t val, void *p) + +void * +ncr_audio_init(const device_t *info) { - wss_t *wss = (wss_t *)p; - uint16_t ports[4] = {0x530, 0xE80, 0xF40, 0x604}; - uint16_t addr; + wss_t *wss = malloc(sizeof(wss_t)); + memset(wss, 0, sizeof(wss_t)); - if (port < 0x102) - return; + opl3_init(&wss->opl); + ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); - wss->opl_enabled = (wss->pos_regs[2] & 0x20) ? 1 : 0; - addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; - - io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - io_removehandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); - io_removehandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); - wss->pos_regs[port & 7] = val; + mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, NULL, wss); + wss->pos_regs[0] = 0x16; + wss->pos_regs[1] = 0x51; - if (wss->pos_regs[2] & 1) { - addr = ports[(wss->pos_regs[2] & 0x18) >> 3]; + sound_add_handler(wss_get_buffer, wss); - if (wss->opl_enabled) - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - - io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); - io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); - } + return wss; } -static uint8_t ncr_audio_mca_feedb(void *p) -{ - wss_t *wss = (wss_t *)p; - return (wss->pos_regs[2] & 1); +void +wss_close(void *priv) +{ + wss_t *wss = (wss_t *) priv; + free(wss); } -void *ncr_audio_init(const device_t *info) + +void +wss_speed_changed(void *priv) { - wss_t *wss = malloc(sizeof(wss_t)); - - memset(wss, 0, sizeof(wss_t)); - - opl3_init(&wss->opl); - ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); - - ad1848_setirq(&wss->ad1848, 7); - ad1848_setdma(&wss->ad1848, 3); - - mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, NULL, wss); - wss->pos_regs[0] = 0x16; - wss->pos_regs[1] = 0x51; - - sound_add_handler(wss_get_buffer, wss); - - return wss; + wss_t *wss = (wss_t *) priv; + ad1848_speed_changed(&wss->ad1848); } -void wss_close(void *p) -{ - wss_t *wss = (wss_t *)p; - free(wss); -} - -void wss_speed_changed(void *p) -{ - wss_t *wss = (wss_t *)p; - - ad1848_speed_changed(&wss->ad1848); -} - -static const device_config_t wss_config[] = -{ - { - "base", "Address", CONFIG_HEX16, "", 0x530, "", { 0 }, - { - { - "0x530", 0x530 - }, - { - "0x604", 0x604 - }, - { - "0xe80", 0xe80 - }, - { - "0xf40", 0xf40 - }, - { - "" - } - } - }, +static const device_config_t wss_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x530, "", { 0 }, { - "opl", "Enable OPL", CONFIG_BINARY, "", 1 - }, - { - "", "", -1 - } + { + "0x530", 0x530 + }, + { + "0x604", 0x604 + }, + { + "0xe80", 0xe80 + }, + { + "0xf40", 0xf40 + }, + { + "" + } + } + }, + { + "opl", "Enable OPL", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } }; + const device_t wss_device = { - "Windows Sound System", - DEVICE_ISA | DEVICE_AT, 0, - wss_init, wss_close, NULL, - { NULL }, - wss_speed_changed, - NULL, - wss_config + "Windows Sound System", + DEVICE_ISA | DEVICE_AT, 0, + wss_init, wss_close, NULL, + { NULL }, + wss_speed_changed, + NULL, + wss_config }; const device_t ncr_business_audio_device = { - "NCR Business Audio", - DEVICE_MCA, 0, - ncr_audio_init, wss_close, NULL, - { NULL }, - wss_speed_changed, - NULL, - NULL + "NCR Business Audio", + DEVICE_MCA, 0, + ncr_audio_init, wss_close, NULL, + { NULL }, + wss_speed_changed, + NULL, + NULL };