2117 lines
65 KiB
C
2117 lines
65 KiB
C
/*
|
|
* 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.
|
|
*
|
|
* Ensoniq AudioPCI (ES1371) emulation.
|
|
*
|
|
*
|
|
*
|
|
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
|
* RichardG, <richardg867@gmail.com>
|
|
* Miran Grca, <mgrca8@gmail.com>
|
|
*
|
|
* Copyright 2008-2021 Sarah Walker.
|
|
* Copyright 2021 RichardG.
|
|
* Copyright 2021 Miran Grca.
|
|
*/
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#define _USE_MATH_DEFINES
|
|
#include <math.h>
|
|
#define HAVE_STDARG_H
|
|
|
|
#include <86box/86box.h>
|
|
#include <86box/device.h>
|
|
#include <86box/gameport.h>
|
|
#include <86box/io.h>
|
|
#include <86box/mem.h>
|
|
#include <86box/midi.h>
|
|
#include <86box/nmi.h>
|
|
#include <86box/pci.h>
|
|
#include <86box/snd_ac97.h>
|
|
#include <86box/sound.h>
|
|
#include <86box/timer.h>
|
|
|
|
#define N 16
|
|
|
|
#define ES1371_NCoef 91
|
|
|
|
static float low_fir_es1371_coef[ES1371_NCoef];
|
|
|
|
typedef struct {
|
|
uint8_t pci_command, pci_serr;
|
|
|
|
uint32_t base_addr;
|
|
|
|
uint8_t int_line;
|
|
|
|
uint16_t pmcsr;
|
|
|
|
uint32_t int_ctrl, int_status,
|
|
legacy_ctrl;
|
|
void *gameport;
|
|
|
|
int mem_page;
|
|
|
|
uint32_t si_cr;
|
|
|
|
uint32_t sr_cir;
|
|
uint16_t sr_ram[128];
|
|
|
|
uint8_t uart_data, uart_ctrl,
|
|
uart_status, uart_res;
|
|
uint32_t uart_fifo[8];
|
|
uint8_t read_fifo_pos, write_fifo_pos;
|
|
|
|
ac97_codec_t *codec;
|
|
uint32_t codec_ctrl;
|
|
|
|
struct {
|
|
uint32_t addr, addr_latch;
|
|
uint16_t count, size;
|
|
|
|
uint16_t samp_ct;
|
|
int curr_samp_ct;
|
|
|
|
pc_timer_t timer;
|
|
uint64_t latch;
|
|
|
|
uint32_t vf, ac;
|
|
|
|
int16_t buffer_l[64], buffer_r[64];
|
|
int buffer_pos, buffer_pos_end;
|
|
|
|
int filtered_l[32], filtered_r[32];
|
|
int f_pos;
|
|
|
|
int16_t out_l, out_r;
|
|
|
|
int32_t vol_l, vol_r;
|
|
} dac[2], adc;
|
|
|
|
int64_t dac_latch, dac_time;
|
|
|
|
int master_vol_l, master_vol_r,
|
|
pcm_vol_l, pcm_vol_r,
|
|
cd_vol_l, cd_vol_r;
|
|
|
|
int card;
|
|
|
|
int pos;
|
|
int16_t buffer[SOUNDBUFLEN * 2];
|
|
|
|
int type;
|
|
} es1371_t;
|
|
|
|
#define LEGACY_SB_ADDR (1 << 29)
|
|
#define LEGACY_SSCAPE_ADDR_SHIFT 27
|
|
#define LEGACY_CODEC_ADDR_SHIFT 25
|
|
#define LEGACY_FORCE_IRQ (1 << 24)
|
|
#define LEGACY_CAPTURE_SLAVE_DMA (1 << 23)
|
|
#define LEGACY_CAPTURE_SLAVE_PIC (1 << 22)
|
|
#define LEGACY_CAPTURE_MASTER_DMA (1 << 21)
|
|
#define LEGACY_CAPTURE_MASTER_PIC (1 << 20)
|
|
#define LEGACY_CAPTURE_ADLIB (1 << 19)
|
|
#define LEGACY_CAPTURE_SB (1 << 18)
|
|
#define LEGACY_CAPTURE_CODEC (1 << 17)
|
|
#define LEGACY_CAPTURE_SSCAPE (1 << 16)
|
|
#define LEGACY_EVENT_SSCAPE (0 << 8)
|
|
#define LEGACY_EVENT_CODEC (1 << 8)
|
|
#define LEGACY_EVENT_SB (2 << 8)
|
|
#define LEGACY_EVENT_ADLIB (3 << 8)
|
|
#define LEGACY_EVENT_MASTER_PIC (4 << 8)
|
|
#define LEGACY_EVENT_MASTER_DMA (5 << 8)
|
|
#define LEGACY_EVENT_SLAVE_PIC (6 << 8)
|
|
#define LEGACY_EVENT_SLAVE_DMA (7 << 8)
|
|
#define LEGACY_EVENT_MASK (7 << 8)
|
|
#define LEGACY_EVENT_ADDR_SHIFT 3
|
|
#define LEGACY_EVENT_ADDR_MASK (0x1f << 3)
|
|
#define LEGACY_EVENT_TYPE_RW (1 << 2)
|
|
#define LEGACY_INT (1 << 0)
|
|
|
|
#define SRC_RAM_WE (1 << 24)
|
|
|
|
#define CODEC_READ (1 << 23)
|
|
#define CODEC_READY (1 << 31)
|
|
|
|
#define INT_DAC1_EN (1 << 6)
|
|
#define INT_DAC2_EN (1 << 5)
|
|
#define INT_UART_EN (1 << 3)
|
|
|
|
#define SI_P2_PAUSE (1 << 12)
|
|
#define SI_P1_PAUSE (1 << 11)
|
|
#define SI_P2_INTR_EN (1 << 9)
|
|
#define SI_P1_INTR_EN (1 << 8)
|
|
|
|
#define INT_STATUS_INTR (1 << 31)
|
|
#define INT_STATUS_UART (1 << 3)
|
|
#define INT_STATUS_DAC1 (1 << 2)
|
|
#define INT_STATUS_DAC2 (1 << 1)
|
|
|
|
#define UART_CTRL_RXINTEN (1 << 7)
|
|
#define UART_CTRL_TXINTEN (3 << 5)
|
|
|
|
#define UART_STATUS_RXINT (1 << 7)
|
|
#define UART_STATUS_TXINT (1 << 2)
|
|
#define UART_STATUS_TXRDY (1 << 1)
|
|
#define UART_STATUS_RXRDY (1 << 0)
|
|
|
|
#define UART_FIFO_BYTE_VALID 0x00000100
|
|
|
|
#define FORMAT_MONO_8 0
|
|
#define FORMAT_STEREO_8 1
|
|
#define FORMAT_MONO_16 2
|
|
#define FORMAT_STEREO_16 3
|
|
|
|
static void es1371_fetch(es1371_t *dev, int dac_nr);
|
|
static void update_legacy(es1371_t *dev, uint32_t old_legacy_ctrl);
|
|
|
|
#ifdef ENABLE_AUDIOPCI_LOG
|
|
int audiopci_do_log = ENABLE_AUDIOPCI_LOG;
|
|
|
|
static void
|
|
audiopci_log(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (audiopci_do_log) {
|
|
va_start(ap, fmt);
|
|
pclog_ex(fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
}
|
|
#else
|
|
# define audiopci_log(fmt, ...)
|
|
#endif
|
|
|
|
static void
|
|
es1371_update_irqs(es1371_t *dev)
|
|
{
|
|
int irq = 0;
|
|
|
|
if ((dev->int_status & INT_STATUS_DAC1) && (dev->si_cr & SI_P1_INTR_EN))
|
|
irq = 1;
|
|
if ((dev->int_status & INT_STATUS_DAC2) && (dev->si_cr & SI_P2_INTR_EN))
|
|
irq = 1;
|
|
|
|
dev->int_status &= ~INT_STATUS_UART;
|
|
|
|
if ((dev->uart_status & UART_STATUS_TXINT) || (dev->uart_status & UART_STATUS_RXINT)) {
|
|
dev->int_status |= INT_STATUS_UART;
|
|
irq = 1;
|
|
}
|
|
|
|
if (irq)
|
|
dev->int_status |= INT_STATUS_INTR;
|
|
else
|
|
dev->int_status &= ~INT_STATUS_INTR;
|
|
|
|
if (dev->legacy_ctrl & LEGACY_FORCE_IRQ)
|
|
irq = 1;
|
|
|
|
if (irq)
|
|
pci_set_irq(dev->card, PCI_INTA);
|
|
else
|
|
pci_clear_irq(dev->card, PCI_INTA);
|
|
}
|
|
|
|
static void
|
|
es1371_update_tx_irq(es1371_t *dev)
|
|
{
|
|
dev->uart_status &= ~UART_STATUS_TXINT;
|
|
|
|
if (((dev->uart_ctrl & UART_CTRL_TXINTEN) == 0x20) && (dev->uart_status & UART_STATUS_TXRDY))
|
|
dev->uart_status |= UART_STATUS_TXINT;
|
|
|
|
es1371_update_irqs(dev);
|
|
}
|
|
|
|
static void
|
|
es1371_set_tx_irq(es1371_t *dev, int set)
|
|
{
|
|
dev->uart_status &= ~UART_STATUS_TXRDY;
|
|
|
|
if (set)
|
|
dev->uart_status |= UART_STATUS_TXRDY;
|
|
|
|
es1371_update_tx_irq(dev);
|
|
}
|
|
|
|
static void
|
|
es1371_update_rx_irq(es1371_t *dev)
|
|
{
|
|
dev->uart_status &= ~UART_STATUS_RXINT;
|
|
|
|
if ((dev->uart_ctrl & UART_CTRL_RXINTEN) && (dev->uart_status & UART_STATUS_RXRDY))
|
|
dev->uart_status |= UART_STATUS_RXINT;
|
|
|
|
es1371_update_irqs(dev);
|
|
}
|
|
|
|
static void
|
|
es1371_set_rx_irq(es1371_t *dev, int set)
|
|
{
|
|
dev->uart_status &= ~UART_STATUS_RXRDY;
|
|
|
|
if (set)
|
|
dev->uart_status |= UART_STATUS_RXRDY;
|
|
|
|
es1371_update_rx_irq(dev);
|
|
}
|
|
|
|
static void
|
|
es1371_scan_fifo(es1371_t *dev)
|
|
{
|
|
if (dev->read_fifo_pos != dev->write_fifo_pos) {
|
|
dev->uart_data = dev->uart_fifo[dev->read_fifo_pos];
|
|
dev->read_fifo_pos = (dev->read_fifo_pos + 1) & 7;
|
|
|
|
es1371_set_rx_irq(dev, 1);
|
|
} else
|
|
es1371_set_rx_irq(dev, 0);
|
|
}
|
|
|
|
static void
|
|
es1371_write_fifo(es1371_t *dev, uint8_t val)
|
|
{
|
|
if (dev->write_fifo_pos < 8) {
|
|
dev->uart_fifo[dev->write_fifo_pos] = val | UART_FIFO_BYTE_VALID;
|
|
dev->write_fifo_pos = (dev->write_fifo_pos + 1) & 7;
|
|
}
|
|
}
|
|
|
|
static void
|
|
es1371_reset_fifo(es1371_t *dev)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
dev->uart_fifo[i] = 0x00000000;
|
|
|
|
dev->read_fifo_pos = dev->write_fifo_pos = 0;
|
|
|
|
es1371_set_rx_irq(dev, 0);
|
|
}
|
|
|
|
static void
|
|
es1371_reset(void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
int i;
|
|
|
|
nmi = 0;
|
|
|
|
/* Interrupt/Chip Select Control Register, Address 00H
|
|
Addressable as byte, word, longword */
|
|
dev->int_ctrl = 0xfc0f0000;
|
|
|
|
/* Interrupt/Chip Select Control Register, Address 00H
|
|
Addressable as longword only */
|
|
dev->int_status = 0x7ffffec0;
|
|
|
|
/* UART Status Register, Address 09H
|
|
Addressable as byte only */
|
|
dev->uart_status = 0x00;
|
|
|
|
/* UART Control Register, Address 09H
|
|
Addressable as byte only */
|
|
dev->uart_ctrl = 0x00;
|
|
|
|
/* UART Reserved Register, Address 0AH
|
|
Addressable as byte only */
|
|
dev->uart_res = 0x00;
|
|
|
|
/* Memory Page Register, Address 0CH
|
|
Addressable as byte, word, longword */
|
|
dev->mem_page = 0x00;
|
|
|
|
/* Sample Rate Converter Interface Register, Address 10H
|
|
Addressable as longword only */
|
|
dev->sr_cir = 0x00000000;
|
|
|
|
/* CODEC Write Register, Address 14H
|
|
Addressable as longword only */
|
|
dev->codec_ctrl = 0x00000000;
|
|
|
|
/* Legacy Control/Status Register, Address 18H
|
|
Addressable as byte, word, longword */
|
|
dev->legacy_ctrl = 0x0000f800;
|
|
|
|
/* Serial Interface Control Register, Address 20H
|
|
Addressable as byte, word, longword */
|
|
dev->si_cr = 0xff800000;
|
|
|
|
/* DAC1 Channel Sample Count Register, Address 24H
|
|
Addressable as word, longword */
|
|
dev->dac[0].samp_ct = 0x00000000;
|
|
dev->dac[0].curr_samp_ct = 0x00000000;
|
|
|
|
/* DAC2 Channel Sample Count Register, Address 28H
|
|
Addressable as word, longword */
|
|
dev->dac[1].samp_ct = 0x00000000;
|
|
dev->dac[1].curr_samp_ct = 0x00000000;
|
|
|
|
/* ADC Channel Sample Count Register, Address 2CH
|
|
Addressable as word, longword */
|
|
dev->adc.samp_ct = 0x00000000;
|
|
dev->adc.curr_samp_ct = 0x00000000;
|
|
|
|
/* DAC1 Frame Register 1, Address 30H, Memory Page 1100b
|
|
Addressable as longword only */
|
|
dev->dac[0].addr_latch = 0x00000000;
|
|
|
|
/* DAC1 Frame Register 2, Address 34H, Memory Page 1100b
|
|
Addressable as longword only */
|
|
dev->dac[0].size = 0x00000000;
|
|
dev->dac[0].count = 0x00000000;
|
|
|
|
/* DAC2 Frame Register 1, Address 38H, Memory Page 1100b
|
|
Addressable as longword only */
|
|
dev->dac[1].addr_latch = 0x00000000;
|
|
|
|
/* DAC2 Frame Register 2, Address 3CH, Memory Page 1100b
|
|
Addressable as longword only */
|
|
dev->dac[1].size = 0x00000000;
|
|
dev->dac[1].count = 0x00000000;
|
|
|
|
/* ADC Frame Register 1, Address 30H, Memory Page 1101b
|
|
Addressable as longword only */
|
|
dev->adc.addr_latch = 0x00000000;
|
|
|
|
/* ADC Frame Register 2, Address 34H, Memory Page 1101b
|
|
Addressable as longword only */
|
|
dev->adc.size = 0x00000000;
|
|
dev->adc.count = 0x00000000;
|
|
|
|
/* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b
|
|
Addressable as longword only */
|
|
for (i = 0; i < 8; i++)
|
|
dev->uart_fifo[i] = 0xffff0000;
|
|
|
|
/* Reset the UART TX. */
|
|
es1371_set_tx_irq(dev, 0);
|
|
|
|
/* Reset the UART (RX) FIFO. */
|
|
es1371_reset_fifo(dev);
|
|
|
|
/* Update interrupts to ensure they're all correctly cleared. */
|
|
es1371_update_irqs(dev);
|
|
}
|
|
|
|
static uint32_t
|
|
es1371_read_frame_reg(es1371_t *dev, int frame, int page)
|
|
{
|
|
uint32_t ret = 0xffffffff;
|
|
|
|
switch (frame) {
|
|
case 0x30:
|
|
switch (page) {
|
|
/* DAC1 Frame Register 1, Address 30H, Memory Page 1100b
|
|
Addressable as longword only */
|
|
case 0xc:
|
|
ret = dev->dac[0].addr_latch;
|
|
break;
|
|
/* ADC Frame Register 1, Address 30H, Memory Page 1101b
|
|
Addressable as longword only */
|
|
case 0xd:
|
|
ret = dev->adc.addr_latch;
|
|
break;
|
|
/* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b
|
|
Addressable as longword only */
|
|
case 0xe:
|
|
case 0xf:
|
|
audiopci_log("[30:%02X] ret = dev->uart_fifo[%02X] = %08X\n", page,
|
|
((page & 0x01) << 2) + ((frame >> 2) & 0x03),
|
|
dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)]);
|
|
ret = dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)];
|
|
break;
|
|
}
|
|
break;
|
|
case 0x34:
|
|
switch (page) {
|
|
/* DAC1 Frame Register 2, Address 34H, Memory Page 1100b
|
|
Addressable as longword only */
|
|
case 0xc:
|
|
ret = dev->dac[0].size | (dev->dac[0].count << 16);
|
|
break;
|
|
/* ADC Frame Register 2, Address 34H, Memory Page 1101b
|
|
Addressable as longword only */
|
|
case 0xd:
|
|
ret = dev->adc.size | (dev->adc.count << 16);
|
|
break;
|
|
/* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b
|
|
Addressable as longword only */
|
|
case 0xe:
|
|
case 0xf:
|
|
audiopci_log("[34:%02X] ret = dev->uart_fifo[%02X] = %08X\n", page,
|
|
((page & 0x01) << 2) + ((frame >> 2) & 0x03),
|
|
dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)]);
|
|
ret = dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)];
|
|
break;
|
|
}
|
|
break;
|
|
case 0x38:
|
|
switch (page) {
|
|
/* DAC2 Frame Register 1, Address 38H, Memory Page 1100b
|
|
Addressable as longword only */
|
|
case 0xc:
|
|
ret = dev->dac[1].addr_latch;
|
|
break;
|
|
/* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b
|
|
Addressable as longword only */
|
|
case 0xe:
|
|
case 0xf:
|
|
audiopci_log("[38:%02X] ret = dev->uart_fifo[%02X] = %08X\n", page,
|
|
((page & 0x01) << 2) + ((frame >> 2) & 0x03),
|
|
dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)]);
|
|
ret = dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)];
|
|
break;
|
|
}
|
|
break;
|
|
case 0x3c:
|
|
switch (page) {
|
|
/* DAC2 Frame Register 2, Address 3CH, Memory Page 1100b
|
|
Addressable as longword only */
|
|
case 0xc:
|
|
ret = dev->dac[1].size | (dev->dac[1].count << 16);
|
|
break;
|
|
/* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b
|
|
Addressable as longword only */
|
|
case 0xe:
|
|
case 0xf:
|
|
audiopci_log("[3C:%02X] ret = dev->uart_fifo[%02X] = %08X\n", page,
|
|
((page & 0x01) << 2) + ((frame >> 2) & 0x03),
|
|
dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)]);
|
|
ret = dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)];
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (page == 0x0e || page == 0x0f) {
|
|
audiopci_log("Read frame = %02x, page = %02x, uart fifo valid = %02x, temp = %03x\n", frame, page, dev->valid, ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
es1371_write_frame_reg(es1371_t *dev, int frame, int page, uint32_t val)
|
|
{
|
|
switch (frame) {
|
|
case 0x30:
|
|
switch (page) {
|
|
/* DAC1 Frame Register 1, Address 30H, Memory Page 1100b
|
|
Addressable as longword only */
|
|
case 0xc:
|
|
dev->dac[0].addr_latch = val;
|
|
break;
|
|
/* ADC Frame Register 1, Address 30H, Memory Page 1101b
|
|
Addressable as longword only */
|
|
case 0xd:
|
|
dev->adc.addr_latch = val;
|
|
break;
|
|
/* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b
|
|
Addressable as longword only */
|
|
case 0xe:
|
|
case 0xf:
|
|
audiopci_log("[30:%02X] dev->uart_fifo[%02X] = %08X\n", page,
|
|
((page & 0x01) << 2) + ((frame >> 2) & 0x03), val);
|
|
dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)] = val;
|
|
break;
|
|
}
|
|
break;
|
|
case 0x34:
|
|
switch (page) {
|
|
/* DAC1 Frame Register 2, Address 34H, Memory Page 1100b
|
|
Addressable as longword only */
|
|
case 0xc:
|
|
dev->dac[0].size = val & 0xffff;
|
|
dev->dac[0].count = val >> 16;
|
|
break;
|
|
/* ADC Frame Register 2, Address 34H, Memory Page 1101b
|
|
Addressable as longword only */
|
|
case 0xd:
|
|
dev->adc.size = val & 0xffff;
|
|
dev->adc.count = val >> 16;
|
|
break;
|
|
/* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b
|
|
Addressable as longword only */
|
|
case 0xe:
|
|
case 0xf:
|
|
audiopci_log("[34:%02X] dev->uart_fifo[%02X] = %08X\n", page,
|
|
((page & 0x01) << 2) + ((frame >> 2) & 0x03), val);
|
|
dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)] = val;
|
|
break;
|
|
}
|
|
break;
|
|
case 0x38:
|
|
switch (page) {
|
|
/* DAC2 Frame Register 1, Address 38H, Memory Page 1100b
|
|
Addressable as longword only */
|
|
case 0xc:
|
|
dev->dac[1].addr_latch = val;
|
|
break;
|
|
/* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b
|
|
Addressable as longword only */
|
|
case 0xe:
|
|
case 0xf:
|
|
audiopci_log("[38:%02X] dev->uart_fifo[%02X] = %08X\n", page,
|
|
((page & 0x01) << 2) + ((frame >> 2) & 0x03), val);
|
|
dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)] = val;
|
|
break;
|
|
}
|
|
break;
|
|
case 0x3c:
|
|
switch (page) {
|
|
/* DAC2 Frame Register 2, Address 3CH, Memory Page 1100b
|
|
Addressable as longword only */
|
|
case 0xc:
|
|
dev->dac[1].size = val & 0xffff;
|
|
dev->dac[1].count = val >> 16;
|
|
break;
|
|
/* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b
|
|
Addressable as longword only */
|
|
case 0xe:
|
|
case 0xf:
|
|
audiopci_log("[3C:%02X] dev->uart_fifo[%02X] = %08X\n", page,
|
|
((page & 0x01) << 2) + ((frame >> 2) & 0x03), val);
|
|
dev->uart_fifo[((page & 0x01) << 2) + ((frame >> 2) & 0x03)] = val;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (page == 0x0e || page == 0x0f) {
|
|
audiopci_log("Write frame = %02x, page = %02x, uart fifo = %08x, val = %02x\n", frame, page, dev->uart_fifo, val);
|
|
}
|
|
}
|
|
|
|
static uint8_t
|
|
es1371_inb(uint16_t port, void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
uint8_t ret = 0xff;
|
|
|
|
switch (port & 0x3f) {
|
|
/* Interrupt/Chip Select Control Register, Address 00H
|
|
Addressable as byte, word, longword */
|
|
case 0x00:
|
|
ret = dev->int_ctrl & 0xff;
|
|
break;
|
|
case 0x01:
|
|
ret = (dev->int_ctrl >> 8) & 0xff;
|
|
break;
|
|
case 0x02:
|
|
ret = (dev->int_ctrl >> 16) & 0x0f;
|
|
break;
|
|
case 0x03:
|
|
ret = ((dev->int_ctrl >> 24) & 0x03) | 0xfc;
|
|
break;
|
|
|
|
/* Interrupt/Chip Select Status Register, Address 04H
|
|
Addressable as longword only, but PCem implements byte access, which
|
|
must be for a reason */
|
|
case 0x04:
|
|
ret = dev->int_status & 0xff;
|
|
audiopci_log("[R] STATUS 0- 7 = %02X\n", ret);
|
|
break;
|
|
case 0x05:
|
|
ret = (dev->int_status >> 8) & 0xff;
|
|
audiopci_log("[R] STATUS 8-15 = %02X\n", ret);
|
|
break;
|
|
case 0x06:
|
|
ret = (dev->int_status >> 16) & 0x0f;
|
|
audiopci_log("[R] STATUS 16-23 = %02X\n", ret);
|
|
break;
|
|
case 0x07:
|
|
ret = ((dev->int_status >> 24) & 0x03) | 0xfc;
|
|
audiopci_log("[R] STATUS 24-31 = %02X\n", ret);
|
|
break;
|
|
|
|
/* UART Data Register, Address 08H
|
|
Addressable as byte only */
|
|
case 0x08:
|
|
ret = dev->uart_data;
|
|
es1371_set_rx_irq(dev, 0);
|
|
audiopci_log("[R] UART DATA = %02X\n", ret);
|
|
break;
|
|
|
|
/* UART Status Register, Address 09H
|
|
Addressable as byte only */
|
|
case 0x09:
|
|
ret = dev->uart_status & 0x87;
|
|
audiopci_log("ES1371 UART Status = %02x\n", dev->uart_status);
|
|
break;
|
|
|
|
/* UART Reserved Register, Address 0AH
|
|
Addressable as byte only */
|
|
case 0x0a:
|
|
ret = dev->uart_res & 0x01;
|
|
audiopci_log("[R] UART RES = %02X\n", ret);
|
|
break;
|
|
|
|
/* Memory Page Register, Address 0CH
|
|
Addressable as byte, word, longword */
|
|
case 0x0c:
|
|
ret = dev->mem_page;
|
|
break;
|
|
case 0x0d ... 0x0e:
|
|
ret = 0x00;
|
|
break;
|
|
|
|
/* Legacy Control/Status Register, Address 18H
|
|
Addressable as byte, word, longword */
|
|
case 0x18:
|
|
ret = dev->legacy_ctrl & 0xfd;
|
|
break;
|
|
case 0x19:
|
|
ret = ((dev->legacy_ctrl >> 8) & 0x07) | 0xf8;
|
|
break;
|
|
case 0x1a:
|
|
ret = dev->legacy_ctrl >> 16;
|
|
break;
|
|
case 0x1b:
|
|
ret = dev->legacy_ctrl >> 24;
|
|
break;
|
|
|
|
/* Serial Interface Control Register, Address 20H
|
|
Addressable as byte, word, longword */
|
|
case 0x20:
|
|
ret = dev->si_cr & 0xff;
|
|
break;
|
|
case 0x21:
|
|
ret = dev->si_cr >> 8;
|
|
break;
|
|
case 0x22:
|
|
ret = (dev->si_cr >> 16) | 0x80;
|
|
break;
|
|
case 0x23:
|
|
ret = 0xff;
|
|
break;
|
|
|
|
default:
|
|
audiopci_log("Bad es1371_inb: port=%04x\n", port);
|
|
}
|
|
|
|
audiopci_log("es1371_inb: port=%04x ret=%02x\n", port, ret);
|
|
return ret;
|
|
}
|
|
|
|
static uint16_t
|
|
es1371_inw(uint16_t port, void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
uint16_t ret = 0xffff;
|
|
|
|
switch (port & 0x3e) {
|
|
/* Interrupt/Chip Select Control Register, Address 00H
|
|
Addressable as byte, word, longword */
|
|
case 0x00:
|
|
ret = dev->int_ctrl & 0xffff;
|
|
break;
|
|
case 0x02:
|
|
ret = ((dev->int_ctrl >> 16) & 0x030f) | 0xfc00;
|
|
break;
|
|
|
|
/* Memory Page Register, Address 0CH
|
|
Addressable as byte, word, longword */
|
|
case 0x0c:
|
|
ret = dev->mem_page;
|
|
break;
|
|
case 0x0e:
|
|
ret = 0x0000;
|
|
break;
|
|
|
|
/* Legacy Control/Status Register, Address 18H
|
|
Addressable as byte, word, longword */
|
|
case 0x18:
|
|
ret = (dev->legacy_ctrl & 0x07fd) | 0xf800;
|
|
break;
|
|
case 0x1a:
|
|
ret = dev->legacy_ctrl >> 16;
|
|
break;
|
|
|
|
/* Serial Interface Control Register, Address 20H
|
|
Addressable as byte, word, longword */
|
|
case 0x20:
|
|
ret = dev->si_cr & 0xffff;
|
|
break;
|
|
case 0x22:
|
|
ret = (dev->si_cr >> 16) | 0xff80;
|
|
break;
|
|
|
|
/* DAC1 Channel Sample Count Register, Address 24H
|
|
Addressable as word, longword */
|
|
case 0x24:
|
|
ret = dev->dac[0].samp_ct;
|
|
break;
|
|
case 0x26:
|
|
ret = dev->dac[0].curr_samp_ct;
|
|
break;
|
|
|
|
/* DAC2 Channel Sample Count Register, Address 28H
|
|
Addressable as word, longword */
|
|
case 0x28:
|
|
ret = dev->dac[1].samp_ct;
|
|
break;
|
|
case 0x2a:
|
|
ret = dev->dac[1].curr_samp_ct;
|
|
break;
|
|
|
|
/* ADC Channel Sample Count Register, Address 2CH
|
|
Addressable as word, longword */
|
|
case 0x2c:
|
|
ret = dev->adc.samp_ct;
|
|
break;
|
|
case 0x2e:
|
|
ret = dev->adc.curr_samp_ct;
|
|
break;
|
|
|
|
case 0x30:
|
|
case 0x34:
|
|
case 0x38:
|
|
case 0x3c:
|
|
ret = es1371_read_frame_reg(dev, port & 0x3c, dev->mem_page) & 0xffff;
|
|
break;
|
|
case 0x32:
|
|
case 0x36:
|
|
case 0x3a:
|
|
case 0x3e:
|
|
ret = es1371_read_frame_reg(dev, port & 0x3c, dev->mem_page) >> 16;
|
|
break;
|
|
}
|
|
|
|
audiopci_log("es1371_inw: port=%04x ret=%04x\n", port, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
es1371_inl(uint16_t port, void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
uint32_t ret = 0xffffffff;
|
|
|
|
switch (port & 0x3c) {
|
|
/* Interrupt/Chip Select Control Register, Address 00H
|
|
Addressable as byte, word, longword */
|
|
case 0x00:
|
|
ret = (dev->int_ctrl & 0x030fffff) | 0xfc000000;
|
|
break;
|
|
|
|
/* Interrupt/Chip Select Status Register, Address 04H
|
|
Addressable as longword only */
|
|
case 0x04:
|
|
ret = dev->int_status;
|
|
audiopci_log("[R] STATUS = %08X\n", ret);
|
|
break;
|
|
|
|
/* Memory Page Register, Address 0CH
|
|
Addressable as byte, word, longword */
|
|
case 0x0c:
|
|
ret = dev->mem_page;
|
|
break;
|
|
|
|
/* Sample Rate Converter Interface Register, Address 10H
|
|
Addressable as longword only */
|
|
case 0x10:
|
|
ret = dev->sr_cir & ~0xffff;
|
|
ret |= dev->sr_ram[dev->sr_cir >> 25];
|
|
break;
|
|
|
|
/* CODEC Read Register, Address 14H
|
|
Addressable as longword only */
|
|
case 0x14:
|
|
ret = dev->codec_ctrl | CODEC_READY;
|
|
break;
|
|
|
|
/* Legacy Control/Status Register, Address 18H
|
|
Addressable as byte, word, longword */
|
|
case 0x18:
|
|
ret = (dev->legacy_ctrl & 0xffff07fd) | 0x0000f800;
|
|
break;
|
|
|
|
/* Serial Interface Control Register, Address 20H
|
|
Addressable as byte, word, longword */
|
|
case 0x20:
|
|
ret = dev->si_cr | 0xff800000;
|
|
break;
|
|
|
|
/* DAC1 Channel Sample Count Register, Address 24H
|
|
Addressable as word, longword */
|
|
case 0x24:
|
|
ret = dev->dac[0].samp_ct | (((uint32_t) dev->dac[0].curr_samp_ct) << 16);
|
|
break;
|
|
|
|
/* DAC2 Channel Sample Count Register, Address 28H
|
|
Addressable as word, longword */
|
|
case 0x28:
|
|
ret = dev->dac[1].samp_ct | (((uint32_t) dev->dac[1].curr_samp_ct) << 16);
|
|
break;
|
|
|
|
/* ADC Channel Sample Count Register, Address 2CH
|
|
Addressable as word, longword */
|
|
case 0x2c:
|
|
ret = dev->adc.samp_ct | (((uint32_t) dev->adc.curr_samp_ct) << 16);
|
|
break;
|
|
|
|
case 0x30:
|
|
case 0x34:
|
|
case 0x38:
|
|
case 0x3c:
|
|
ret = es1371_read_frame_reg(dev, port & 0x3c, dev->mem_page);
|
|
break;
|
|
}
|
|
|
|
audiopci_log("es1371_inl: port=%04x ret=%08x\n", port, ret);
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
es1371_outb(uint16_t port, uint8_t val, void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
uint32_t old_legacy_ctrl;
|
|
|
|
audiopci_log("es1371_outb: port=%04x val=%02x\n", port, val);
|
|
|
|
switch (port & 0x3f) {
|
|
/* Interrupt/Chip Select Control Register, Address 00H
|
|
Addressable as byte, word, longword */
|
|
case 0x00:
|
|
if (!(dev->int_ctrl & INT_DAC1_EN) && (val & INT_DAC1_EN)) {
|
|
dev->dac[0].addr = dev->dac[0].addr_latch;
|
|
dev->dac[0].buffer_pos = 0;
|
|
dev->dac[0].buffer_pos_end = 0;
|
|
es1371_fetch(dev, 0);
|
|
}
|
|
if (!(dev->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) {
|
|
dev->dac[1].addr = dev->dac[1].addr_latch;
|
|
dev->dac[1].buffer_pos = 0;
|
|
dev->dac[1].buffer_pos_end = 0;
|
|
es1371_fetch(dev, 1);
|
|
}
|
|
dev->int_ctrl = (dev->int_ctrl & 0xffffff00) | val;
|
|
break;
|
|
case 0x01:
|
|
dev->int_ctrl = (dev->int_ctrl & 0xffff00ff) | (val << 8);
|
|
break;
|
|
case 0x02:
|
|
dev->int_ctrl = (dev->int_ctrl & 0xff00ffff) | (val << 16);
|
|
break;
|
|
case 0x03:
|
|
dev->int_ctrl = (dev->int_ctrl & 0x00ffffff) | (val << 24);
|
|
gameport_remap(dev->gameport, 0x200 | ((val & 0x03) << 3));
|
|
break;
|
|
|
|
/* UART Data Register, Address 08H
|
|
Addressable as byte only */
|
|
case 0x08:
|
|
audiopci_log("MIDI data = %02x\n", val);
|
|
/* TX does not use FIFO. */
|
|
midi_raw_out_byte(val);
|
|
es1371_set_tx_irq(dev, 1);
|
|
break;
|
|
|
|
/* UART Control Register, Address 09H
|
|
Addressable as byte only */
|
|
case 0x09:
|
|
audiopci_log("[W] UART CTRL = %02X\n", val);
|
|
dev->uart_ctrl = val & 0xe3;
|
|
|
|
if ((val & 0x03) == 0x03) {
|
|
/* Reset TX */
|
|
es1371_set_tx_irq(dev, 1);
|
|
|
|
/* Software reset */
|
|
es1371_reset_fifo(dev);
|
|
} else {
|
|
es1371_set_tx_irq(dev, 1);
|
|
|
|
es1371_update_tx_irq(dev);
|
|
es1371_update_rx_irq(dev);
|
|
}
|
|
break;
|
|
|
|
/* UART Reserved Register, Address 0AH
|
|
Addressable as byte only */
|
|
case 0x0a:
|
|
audiopci_log("[W] UART RES = %02X\n", val);
|
|
dev->uart_res = val & 0x01;
|
|
break;
|
|
|
|
/* Memory Page Register, Address 0CH
|
|
Addressable as byte, word, longword */
|
|
case 0x0c:
|
|
dev->mem_page = val & 0xf;
|
|
break;
|
|
case 0x0d ... 0x0f:
|
|
break;
|
|
|
|
/* Legacy Control/Status Register, Address 18H
|
|
Addressable as byte, word, longword */
|
|
case 0x18:
|
|
dev->legacy_ctrl |= LEGACY_INT;
|
|
break;
|
|
case 0x1a:
|
|
old_legacy_ctrl = dev->legacy_ctrl;
|
|
dev->legacy_ctrl = (dev->legacy_ctrl & 0xff00ffff) | (val << 16);
|
|
update_legacy(dev, old_legacy_ctrl);
|
|
break;
|
|
case 0x1b:
|
|
old_legacy_ctrl = dev->legacy_ctrl;
|
|
dev->legacy_ctrl = (dev->legacy_ctrl & 0x00ffffff) | (val << 24);
|
|
es1371_update_irqs(dev);
|
|
update_legacy(dev, old_legacy_ctrl);
|
|
break;
|
|
|
|
/* Serial Interface Control Register, Address 20H
|
|
Addressable as byte, word, longword */
|
|
case 0x20:
|
|
dev->si_cr = (dev->si_cr & 0xffffff00) | val;
|
|
break;
|
|
case 0x21:
|
|
dev->si_cr = (dev->si_cr & 0xffff00ff) | (val << 8);
|
|
if (!(dev->si_cr & SI_P1_INTR_EN))
|
|
dev->int_status &= ~INT_STATUS_DAC1;
|
|
if (!(dev->si_cr & SI_P2_INTR_EN))
|
|
dev->int_status &= ~INT_STATUS_DAC2;
|
|
es1371_update_irqs(dev);
|
|
break;
|
|
case 0x22:
|
|
dev->si_cr = (dev->si_cr & 0xff80ffff) | ((val & 0x7f) << 16);
|
|
break;
|
|
|
|
default:
|
|
audiopci_log("Bad es1371_outb: port=%04x val=%02x\n", port, val);
|
|
}
|
|
}
|
|
|
|
static void
|
|
es1371_outw(uint16_t port, uint16_t val, void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
uint32_t old_legacy_ctrl;
|
|
|
|
switch (port & 0x3f) {
|
|
/* Interrupt/Chip Select Control Register, Address 00H
|
|
Addressable as byte, word, longword */
|
|
case 0x00:
|
|
if (!(dev->int_ctrl & INT_DAC1_EN) && (val & INT_DAC1_EN)) {
|
|
dev->dac[0].addr = dev->dac[0].addr_latch;
|
|
dev->dac[0].buffer_pos = 0;
|
|
dev->dac[0].buffer_pos_end = 0;
|
|
es1371_fetch(dev, 0);
|
|
}
|
|
if (!(dev->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) {
|
|
dev->dac[1].addr = dev->dac[1].addr_latch;
|
|
dev->dac[1].buffer_pos = 0;
|
|
dev->dac[1].buffer_pos_end = 0;
|
|
es1371_fetch(dev, 1);
|
|
}
|
|
dev->int_ctrl = (dev->int_ctrl & 0xffff0000) | val;
|
|
break;
|
|
case 0x02:
|
|
dev->int_ctrl = (dev->int_ctrl & 0x0000ffff) | (val << 16);
|
|
gameport_remap(dev->gameport, 0x200 | ((val & 0x0300) >> 5));
|
|
break;
|
|
|
|
/* Memory Page Register, Address 0CH
|
|
Addressable as byte, word, longword */
|
|
case 0x0c:
|
|
dev->mem_page = val & 0xf;
|
|
break;
|
|
case 0x0e:
|
|
break;
|
|
|
|
/* Legacy Control/Status Register, Address 18H
|
|
Addressable as byte, word, longword */
|
|
case 0x18:
|
|
dev->legacy_ctrl |= LEGACY_INT;
|
|
break;
|
|
case 0x1a:
|
|
old_legacy_ctrl = dev->legacy_ctrl;
|
|
dev->legacy_ctrl = (dev->legacy_ctrl & 0x0000ffff) | (val << 16);
|
|
es1371_update_irqs(dev);
|
|
update_legacy(dev, old_legacy_ctrl);
|
|
break;
|
|
|
|
/* Serial Interface Control Register, Address 20H
|
|
Addressable as byte, word, longword */
|
|
case 0x20:
|
|
dev->si_cr = (dev->si_cr & 0xffff0000) | val;
|
|
if (!(dev->si_cr & SI_P1_INTR_EN))
|
|
dev->int_status &= ~INT_STATUS_DAC1;
|
|
if (!(dev->si_cr & SI_P2_INTR_EN))
|
|
dev->int_status &= ~INT_STATUS_DAC2;
|
|
es1371_update_irqs(dev);
|
|
break;
|
|
case 0x22:
|
|
dev->si_cr = (dev->si_cr & 0xff80ffff) | ((val & 0x007f) << 16);
|
|
break;
|
|
|
|
/* DAC1 Channel Sample Count Register, Address 24H
|
|
Addressable as word, longword */
|
|
case 0x24:
|
|
dev->dac[0].samp_ct = val;
|
|
break;
|
|
|
|
/* DAC2 Channel Sample Count Register, Address 28H
|
|
Addressable as word, longword */
|
|
case 0x28:
|
|
dev->dac[1].samp_ct = val;
|
|
break;
|
|
|
|
/* ADC Channel Sample Count Register, Address 2CH
|
|
Addressable as word, longword */
|
|
case 0x2c:
|
|
dev->adc.samp_ct = val;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
es1371_outl(uint16_t port, uint32_t val, void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
uint32_t old_legacy_ctrl;
|
|
|
|
audiopci_log("es1371_outl: port=%04x val=%08x\n", port, val);
|
|
|
|
switch (port & 0x3f) {
|
|
/* Interrupt/Chip Select Control Register, Address 00H
|
|
Addressable as byte, word, longword */
|
|
case 0x00:
|
|
if (!(dev->int_ctrl & INT_DAC1_EN) && (val & INT_DAC1_EN)) {
|
|
dev->dac[0].addr = dev->dac[0].addr_latch;
|
|
dev->dac[0].buffer_pos = 0;
|
|
dev->dac[0].buffer_pos_end = 0;
|
|
es1371_fetch(dev, 0);
|
|
}
|
|
if (!(dev->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) {
|
|
dev->dac[1].addr = dev->dac[1].addr_latch;
|
|
dev->dac[1].buffer_pos = 0;
|
|
dev->dac[1].buffer_pos_end = 0;
|
|
es1371_fetch(dev, 1);
|
|
}
|
|
dev->int_ctrl = val;
|
|
gameport_remap(dev->gameport, 0x200 | ((val & 0x03000000) >> 21));
|
|
break;
|
|
|
|
/* Interrupt/Chip Select Status Register, Address 04H
|
|
Addressable as longword only */
|
|
case 0x04:
|
|
audiopci_log("[W] STATUS = %08X\n", val);
|
|
break;
|
|
|
|
/* Memory Page Register, Address 0CH
|
|
Addressable as byte, word, longword */
|
|
case 0x0c:
|
|
dev->mem_page = val & 0xf;
|
|
break;
|
|
|
|
/* Sample Rate Converter Interface Register, Address 10H
|
|
Addressable as longword only */
|
|
case 0x10:
|
|
dev->sr_cir = val & 0xfff8ffff; /*Bits 16 to 18 are undefined*/
|
|
if (dev->sr_cir & SRC_RAM_WE) {
|
|
dev->sr_ram[dev->sr_cir >> 25] = val & 0xffff;
|
|
switch (dev->sr_cir >> 25) {
|
|
case 0x71:
|
|
dev->dac[0].vf = (dev->dac[0].vf & ~0x1f8000) | ((val & 0xfc00) << 5);
|
|
dev->dac[0].ac = (dev->dac[0].ac & ~0x7f8000) | ((val & 0x00ff) << 15);
|
|
dev->dac[0].f_pos = 0;
|
|
break;
|
|
case 0x72:
|
|
dev->dac[0].ac = (dev->dac[0].ac & ~0x7fff) | (val & 0x7fff);
|
|
break;
|
|
case 0x73:
|
|
dev->dac[0].vf = (dev->dac[0].vf & ~0x7fff) | (val & 0x7fff);
|
|
break;
|
|
|
|
case 0x75:
|
|
dev->dac[1].vf = (dev->dac[1].vf & ~0x1f8000) | ((val & 0xfc00) << 5);
|
|
dev->dac[1].ac = (dev->dac[1].ac & ~0x7f8000) | ((val & 0x00ff) << 15);
|
|
dev->dac[1].f_pos = 0;
|
|
break;
|
|
case 0x76:
|
|
dev->dac[1].ac = (dev->dac[1].ac & ~0x7fff) | (val & 0x7fff);
|
|
break;
|
|
case 0x77:
|
|
dev->dac[1].vf = (dev->dac[1].vf & ~0x7fff) | (val & 0x7fff);
|
|
break;
|
|
|
|
case 0x7c:
|
|
dev->dac[0].vol_l = (int32_t) (int16_t) (val & 0xffff);
|
|
break;
|
|
case 0x7d:
|
|
dev->dac[0].vol_r = (int32_t) (int16_t) (val & 0xffff);
|
|
break;
|
|
case 0x7e:
|
|
dev->dac[1].vol_l = (int32_t) (int16_t) (val & 0xffff);
|
|
break;
|
|
case 0x7f:
|
|
dev->dac[1].vol_r = (int32_t) (int16_t) (val & 0xffff);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* CODEC Write Register, Address 14H
|
|
Addressable as longword only */
|
|
case 0x14:
|
|
if (val & CODEC_READ) {
|
|
dev->codec_ctrl &= 0x00ff0000;
|
|
dev->codec_ctrl |= ac97_codec_readw(dev->codec, val >> 16);
|
|
} else {
|
|
dev->codec_ctrl = val & 0x00ffffff;
|
|
ac97_codec_writew(dev->codec, val >> 16, val);
|
|
|
|
ac97_codec_getattn(dev->codec, 0x02, &dev->master_vol_l, &dev->master_vol_r);
|
|
ac97_codec_getattn(dev->codec, 0x18, &dev->pcm_vol_l, &dev->pcm_vol_r);
|
|
ac97_codec_getattn(dev->codec, 0x12, &dev->cd_vol_l, &dev->cd_vol_r);
|
|
}
|
|
break;
|
|
|
|
/* Legacy Control/Status Register, Address 18H
|
|
Addressable as byte, word, longword */
|
|
case 0x18:
|
|
old_legacy_ctrl = dev->legacy_ctrl;
|
|
dev->legacy_ctrl = (dev->legacy_ctrl & 0x0000ffff) | (val & 0xffff0000);
|
|
dev->legacy_ctrl |= LEGACY_INT;
|
|
es1371_update_irqs(dev);
|
|
update_legacy(dev, old_legacy_ctrl);
|
|
break;
|
|
|
|
/* Serial Interface Control Register, Address 20H
|
|
Addressable as byte, word, longword */
|
|
case 0x20:
|
|
dev->si_cr = (val & 0x007fffff) | 0xff800000;
|
|
if (!(dev->si_cr & SI_P1_INTR_EN))
|
|
dev->int_status &= ~INT_STATUS_DAC1;
|
|
if (!(dev->si_cr & SI_P2_INTR_EN))
|
|
dev->int_status &= ~INT_STATUS_DAC2;
|
|
es1371_update_irqs(dev);
|
|
break;
|
|
|
|
/* DAC1 Channel Sample Count Register, Address 24H
|
|
Addressable as word, longword */
|
|
case 0x24:
|
|
dev->dac[0].samp_ct = val & 0xffff;
|
|
break;
|
|
|
|
/* DAC2 Channel Sample Count Register, Address 28H
|
|
Addressable as word, longword */
|
|
case 0x28:
|
|
dev->dac[1].samp_ct = val & 0xffff;
|
|
break;
|
|
|
|
/* ADC Channel Sample Count Register, Address 2CH
|
|
Addressable as word, longword */
|
|
case 0x2c:
|
|
dev->adc.samp_ct = val & 0xffff;
|
|
break;
|
|
|
|
case 0x30:
|
|
case 0x34:
|
|
case 0x38:
|
|
case 0x3c:
|
|
es1371_write_frame_reg(dev, port & 0x3c, dev->mem_page, val);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
capture_event(es1371_t *dev, int type, int rw, uint16_t port)
|
|
{
|
|
dev->legacy_ctrl &= ~(LEGACY_EVENT_MASK | LEGACY_EVENT_ADDR_MASK);
|
|
dev->legacy_ctrl |= type;
|
|
if (rw)
|
|
dev->legacy_ctrl |= LEGACY_EVENT_TYPE_RW;
|
|
else
|
|
dev->legacy_ctrl &= ~LEGACY_EVENT_TYPE_RW;
|
|
dev->legacy_ctrl |= ((port << LEGACY_EVENT_ADDR_SHIFT) & LEGACY_EVENT_ADDR_MASK);
|
|
dev->legacy_ctrl &= ~LEGACY_INT;
|
|
nmi = 1;
|
|
}
|
|
|
|
static void
|
|
capture_write_sscape(uint16_t port, uint8_t val, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_SSCAPE, 1, port);
|
|
}
|
|
|
|
static void
|
|
capture_write_codec(uint16_t port, uint8_t val, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_CODEC, 1, port);
|
|
}
|
|
|
|
static void
|
|
capture_write_sb(uint16_t port, uint8_t val, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_SB, 1, port);
|
|
}
|
|
|
|
static void
|
|
capture_write_adlib(uint16_t port, uint8_t val, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_ADLIB, 1, port);
|
|
}
|
|
|
|
static void
|
|
capture_write_master_pic(uint16_t port, uint8_t val, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_MASTER_PIC, 1, port);
|
|
}
|
|
|
|
static void
|
|
capture_write_master_dma(uint16_t port, uint8_t val, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_MASTER_DMA, 1, port);
|
|
}
|
|
|
|
static void
|
|
capture_write_slave_pic(uint16_t port, uint8_t val, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_SLAVE_PIC, 1, port);
|
|
}
|
|
|
|
static void
|
|
capture_write_slave_dma(uint16_t port, uint8_t val, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_SLAVE_DMA, 1, port);
|
|
}
|
|
|
|
static uint8_t
|
|
capture_read_sscape(uint16_t port, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_SSCAPE, 0, port);
|
|
return 0xff;
|
|
}
|
|
|
|
static uint8_t
|
|
capture_read_codec(uint16_t port, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_CODEC, 0, port);
|
|
return 0xff;
|
|
}
|
|
|
|
static uint8_t
|
|
capture_read_sb(uint16_t port, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_SB, 0, port);
|
|
return 0xff;
|
|
}
|
|
|
|
static uint8_t
|
|
capture_read_adlib(uint16_t port, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_ADLIB, 0, port);
|
|
return 0xff;
|
|
}
|
|
|
|
static uint8_t
|
|
capture_read_master_pic(uint16_t port, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_MASTER_PIC, 0, port);
|
|
return 0xff;
|
|
}
|
|
|
|
static uint8_t
|
|
capture_read_master_dma(uint16_t port, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_MASTER_DMA, 0, port);
|
|
return 0xff;
|
|
}
|
|
|
|
static uint8_t
|
|
capture_read_slave_pic(uint16_t port, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_SLAVE_PIC, 0, port);
|
|
return 0xff;
|
|
}
|
|
|
|
static uint8_t
|
|
capture_read_slave_dma(uint16_t port, void *p)
|
|
{
|
|
capture_event(p, LEGACY_EVENT_SLAVE_DMA, 0, port);
|
|
return 0xff;
|
|
}
|
|
|
|
static void
|
|
update_legacy(es1371_t *dev, uint32_t old_legacy_ctrl)
|
|
{
|
|
if (old_legacy_ctrl & LEGACY_CAPTURE_SSCAPE) {
|
|
switch ((old_legacy_ctrl >> LEGACY_SSCAPE_ADDR_SHIFT) & 3) {
|
|
case 0:
|
|
io_removehandler(0x0320, 0x0008,
|
|
capture_read_sscape, NULL, NULL,
|
|
capture_write_sscape, NULL, NULL, dev);
|
|
break;
|
|
case 1:
|
|
io_removehandler(0x0330, 0x0008,
|
|
capture_read_sscape, NULL, NULL,
|
|
capture_write_sscape, NULL, NULL, dev);
|
|
break;
|
|
case 2:
|
|
io_removehandler(0x0340, 0x0008,
|
|
capture_read_sscape, NULL, NULL,
|
|
capture_write_sscape, NULL, NULL, dev);
|
|
break;
|
|
case 3:
|
|
io_removehandler(0x0350, 0x0008,
|
|
capture_read_sscape, NULL, NULL,
|
|
capture_write_sscape, NULL, NULL, dev);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (old_legacy_ctrl & LEGACY_CAPTURE_CODEC) {
|
|
switch ((old_legacy_ctrl >> LEGACY_CODEC_ADDR_SHIFT) & 3) {
|
|
case 0:
|
|
io_removehandler(0x0530, 0x0008,
|
|
capture_read_codec, NULL, NULL,
|
|
capture_write_codec, NULL, NULL, dev);
|
|
break;
|
|
case 2:
|
|
io_removehandler(0x0e80, 0x0008,
|
|
capture_read_codec, NULL, NULL,
|
|
capture_write_codec, NULL, NULL, dev);
|
|
break;
|
|
case 3:
|
|
io_removehandler(0x0f40, 0x0008,
|
|
capture_read_codec, NULL, NULL,
|
|
capture_write_codec, NULL, NULL, dev);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (old_legacy_ctrl & LEGACY_CAPTURE_SB) {
|
|
if (!(old_legacy_ctrl & LEGACY_SB_ADDR)) {
|
|
io_removehandler(0x0220, 0x0010,
|
|
capture_read_sb, NULL, NULL,
|
|
capture_write_sb, NULL, NULL, dev);
|
|
} else {
|
|
io_removehandler(0x0240, 0x0010,
|
|
capture_read_sb, NULL, NULL,
|
|
capture_write_sb, NULL, NULL, dev);
|
|
}
|
|
}
|
|
|
|
if (old_legacy_ctrl & LEGACY_CAPTURE_ADLIB) {
|
|
io_removehandler(0x0388, 0x0004,
|
|
capture_read_adlib, NULL, NULL,
|
|
capture_write_adlib, NULL, NULL, dev);
|
|
}
|
|
|
|
if (old_legacy_ctrl & LEGACY_CAPTURE_MASTER_PIC) {
|
|
io_removehandler(0x0020, 0x0002,
|
|
capture_read_master_pic, NULL, NULL,
|
|
capture_write_master_pic, NULL, NULL, dev);
|
|
}
|
|
|
|
if (old_legacy_ctrl & LEGACY_CAPTURE_MASTER_DMA) {
|
|
io_removehandler(0x0000, 0x0010,
|
|
capture_read_master_dma, NULL, NULL,
|
|
capture_write_master_dma, NULL, NULL, dev);
|
|
}
|
|
|
|
if (old_legacy_ctrl & LEGACY_CAPTURE_SLAVE_PIC) {
|
|
io_removehandler(0x00a0, 0x0002,
|
|
capture_read_slave_pic, NULL, NULL,
|
|
capture_write_slave_pic, NULL, NULL, dev);
|
|
}
|
|
|
|
if (old_legacy_ctrl & LEGACY_CAPTURE_SLAVE_DMA) {
|
|
io_removehandler(0x00c0, 0x0020,
|
|
capture_read_slave_dma, NULL, NULL,
|
|
capture_write_slave_dma, NULL, NULL, dev);
|
|
}
|
|
|
|
if (dev->legacy_ctrl & LEGACY_CAPTURE_SSCAPE) {
|
|
switch ((dev->legacy_ctrl >> LEGACY_SSCAPE_ADDR_SHIFT) & 3) {
|
|
case 0:
|
|
io_sethandler(0x0320, 0x0008,
|
|
capture_read_sscape, NULL, NULL,
|
|
capture_write_sscape, NULL, NULL, dev);
|
|
break;
|
|
case 1:
|
|
io_sethandler(0x0330, 0x0008,
|
|
capture_read_sscape, NULL, NULL,
|
|
capture_write_sscape, NULL, NULL, dev);
|
|
break;
|
|
case 2:
|
|
io_sethandler(0x0340, 0x0008,
|
|
capture_read_sscape, NULL, NULL,
|
|
capture_write_sscape, NULL, NULL, dev);
|
|
break;
|
|
case 3:
|
|
io_sethandler(0x0350, 0x0008,
|
|
capture_read_sscape, NULL, NULL,
|
|
capture_write_sscape, NULL, NULL, dev);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (dev->legacy_ctrl & LEGACY_CAPTURE_CODEC) {
|
|
switch ((dev->legacy_ctrl >> LEGACY_CODEC_ADDR_SHIFT) & 3) {
|
|
case 0:
|
|
io_sethandler(0x0530, 0x0008,
|
|
capture_read_codec, NULL, NULL,
|
|
capture_write_codec, NULL, NULL, dev);
|
|
break;
|
|
case 2:
|
|
io_sethandler(0x0e80, 0x0008,
|
|
capture_read_codec, NULL, NULL,
|
|
capture_write_codec, NULL, NULL, dev);
|
|
break;
|
|
case 3:
|
|
io_sethandler(0x0f40, 0x0008,
|
|
capture_read_codec, NULL, NULL,
|
|
capture_write_codec, NULL, NULL, dev);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (dev->legacy_ctrl & LEGACY_CAPTURE_SB) {
|
|
if (!(dev->legacy_ctrl & LEGACY_SB_ADDR)) {
|
|
io_sethandler(0x0220, 0x0010,
|
|
capture_read_sb, NULL, NULL,
|
|
capture_write_sb, NULL, NULL, dev);
|
|
} else {
|
|
io_sethandler(0x0240, 0x0010,
|
|
capture_read_sb, NULL, NULL,
|
|
capture_write_sb, NULL, NULL, dev);
|
|
}
|
|
}
|
|
|
|
if (dev->legacy_ctrl & LEGACY_CAPTURE_ADLIB) {
|
|
io_sethandler(0x0388, 0x0004,
|
|
capture_read_adlib, NULL, NULL,
|
|
capture_write_adlib, NULL, NULL, dev);
|
|
}
|
|
|
|
if (dev->legacy_ctrl & LEGACY_CAPTURE_MASTER_PIC) {
|
|
io_sethandler(0x0020, 0x0002,
|
|
capture_read_master_pic, NULL, NULL,
|
|
capture_write_master_pic, NULL, NULL, dev);
|
|
}
|
|
|
|
if (dev->legacy_ctrl & LEGACY_CAPTURE_MASTER_DMA) {
|
|
io_sethandler(0x0000, 0x0010,
|
|
capture_read_master_dma, NULL, NULL,
|
|
capture_write_master_dma, NULL, NULL, dev);
|
|
}
|
|
|
|
if (dev->legacy_ctrl & LEGACY_CAPTURE_SLAVE_PIC) {
|
|
io_sethandler(0x00a0, 0x0002,
|
|
capture_read_slave_pic, NULL, NULL,
|
|
capture_write_slave_pic, NULL, NULL, dev);
|
|
}
|
|
|
|
if (dev->legacy_ctrl & LEGACY_CAPTURE_SLAVE_DMA) {
|
|
io_sethandler(0x00c0, 0x0020,
|
|
capture_read_slave_dma, NULL, NULL,
|
|
capture_write_slave_dma, NULL, NULL, dev);
|
|
}
|
|
}
|
|
|
|
static uint8_t
|
|
es1371_pci_read(int func, int addr, void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
|
|
if (func > 0)
|
|
return 0xff;
|
|
|
|
if ((addr > 0x3f) && ((addr < 0xdc) || (addr > 0xe1)))
|
|
return 0x00;
|
|
|
|
switch (addr) {
|
|
case 0x00:
|
|
return 0x74; /* Ensoniq */
|
|
case 0x01:
|
|
return 0x12;
|
|
|
|
case 0x02:
|
|
return 0x71; /* ES1371 */
|
|
case 0x03:
|
|
return 0x13;
|
|
|
|
case 0x04:
|
|
return dev->pci_command;
|
|
case 0x05:
|
|
return dev->pci_serr;
|
|
|
|
case 0x06:
|
|
return 0x10; /* Supports ACPI */
|
|
case 0x07:
|
|
return 0x00;
|
|
|
|
case 0x08:
|
|
return 0x08; /* Revision ID - 0x02 (datasheet, VMware) has issues with the 2001 Creative WDM driver */
|
|
case 0x09:
|
|
return 0x00; /* Multimedia audio device */
|
|
case 0x0a:
|
|
return 0x01;
|
|
case 0x0b:
|
|
return 0x04;
|
|
|
|
case 0x10:
|
|
return 0x01 | (dev->base_addr & 0xc0); /* memBaseAddr */
|
|
case 0x11:
|
|
return dev->base_addr >> 8;
|
|
case 0x12:
|
|
return dev->base_addr >> 16;
|
|
case 0x13:
|
|
return dev->base_addr >> 24;
|
|
|
|
case 0x2c:
|
|
return 0x74; /* Subsystem vendor ID */
|
|
case 0x2d:
|
|
return 0x12;
|
|
case 0x2e:
|
|
return 0x71;
|
|
case 0x2f:
|
|
return 0x13;
|
|
|
|
case 0x34:
|
|
return 0xdc; /* Capabilites pointer */
|
|
|
|
case 0x3c:
|
|
return dev->int_line;
|
|
case 0x3d:
|
|
return 0x01; /* INTA */
|
|
|
|
case 0x3e:
|
|
return 0xc; /* Minimum grant */
|
|
case 0x3f:
|
|
return 0x80; /* Maximum latency */
|
|
|
|
case 0xdc:
|
|
return 0x01; /* Capabilities identifier */
|
|
case 0xdd:
|
|
return 0x00; /* Next item pointer */
|
|
case 0xde:
|
|
return 0x31; /* Power management capabilities */
|
|
case 0xdf:
|
|
return 0x6c;
|
|
|
|
case 0xe0:
|
|
return dev->pmcsr & 0xff;
|
|
case 0xe1:
|
|
return dev->pmcsr >> 8;
|
|
}
|
|
|
|
return 0x00;
|
|
}
|
|
|
|
static void
|
|
es1371_io_set(es1371_t *dev, int set)
|
|
{
|
|
if (dev->pci_command & PCI_COMMAND_IO) {
|
|
io_handler(set, dev->base_addr, 0x0040,
|
|
es1371_inb, es1371_inw, es1371_inl,
|
|
es1371_outb, es1371_outw, es1371_outl, dev);
|
|
}
|
|
}
|
|
|
|
static void
|
|
es1371_pci_write(int func, int addr, uint8_t val, void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
|
|
if (func)
|
|
return;
|
|
|
|
switch (addr) {
|
|
case 0x04:
|
|
es1371_io_set(dev, 0);
|
|
dev->pci_command = val & 0x05;
|
|
es1371_io_set(dev, 1);
|
|
break;
|
|
case 0x05:
|
|
dev->pci_serr = val & 1;
|
|
break;
|
|
|
|
case 0x10:
|
|
es1371_io_set(dev, 0);
|
|
dev->base_addr = (dev->base_addr & 0xffffff00) | (val & 0xc0);
|
|
es1371_io_set(dev, 1);
|
|
break;
|
|
case 0x11:
|
|
es1371_io_set(dev, 0);
|
|
dev->base_addr = (dev->base_addr & 0xffff00c0) | (val << 8);
|
|
es1371_io_set(dev, 1);
|
|
break;
|
|
case 0x12:
|
|
dev->base_addr = (dev->base_addr & 0xff00ffc0) | (val << 16);
|
|
break;
|
|
case 0x13:
|
|
dev->base_addr = (dev->base_addr & 0x00ffffc0) | (val << 24);
|
|
break;
|
|
|
|
case 0x3c:
|
|
dev->int_line = val;
|
|
break;
|
|
|
|
case 0xe0:
|
|
dev->pmcsr = (dev->pmcsr & 0xff00) | (val & 0x03);
|
|
break;
|
|
case 0xe1:
|
|
dev->pmcsr = (dev->pmcsr & 0x00ff) | ((val & 0x01) << 8);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
es1371_fetch(es1371_t *dev, int dac_nr)
|
|
{
|
|
if (dev->si_cr & (dac_nr ? SI_P2_PAUSE : SI_P1_PAUSE))
|
|
return;
|
|
|
|
int format = dac_nr ? ((dev->si_cr >> 2) & 3) : (dev->si_cr & 3);
|
|
int pos = dev->dac[dac_nr].buffer_pos & 63;
|
|
int c;
|
|
|
|
switch (format) {
|
|
case FORMAT_MONO_8:
|
|
for (c = 0; c < 32; c += 4) {
|
|
dev->dac[dac_nr].buffer_l[(pos + c) & 63] = dev->dac[dac_nr].buffer_r[(pos + c) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr) ^ 0x80) << 8;
|
|
dev->dac[dac_nr].buffer_l[(pos + c + 1) & 63] = dev->dac[dac_nr].buffer_r[(pos + c + 1) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr + 1) ^ 0x80) << 8;
|
|
dev->dac[dac_nr].buffer_l[(pos + c + 2) & 63] = dev->dac[dac_nr].buffer_r[(pos + c + 2) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr + 2) ^ 0x80) << 8;
|
|
dev->dac[dac_nr].buffer_l[(pos + c + 3) & 63] = dev->dac[dac_nr].buffer_r[(pos + c + 3) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr + 3) ^ 0x80) << 8;
|
|
dev->dac[dac_nr].addr += 4;
|
|
|
|
dev->dac[dac_nr].buffer_pos_end += 4;
|
|
dev->dac[dac_nr].count++;
|
|
|
|
if (dev->dac[dac_nr].count > dev->dac[dac_nr].size) {
|
|
dev->dac[dac_nr].count = 0;
|
|
dev->dac[dac_nr].addr = dev->dac[dac_nr].addr_latch;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FORMAT_STEREO_8:
|
|
for (c = 0; c < 16; c += 2) {
|
|
dev->dac[dac_nr].buffer_l[(pos + c) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr) ^ 0x80) << 8;
|
|
dev->dac[dac_nr].buffer_r[(pos + c) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr + 1) ^ 0x80) << 8;
|
|
dev->dac[dac_nr].buffer_l[(pos + c + 1) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr + 2) ^ 0x80) << 8;
|
|
dev->dac[dac_nr].buffer_r[(pos + c + 1) & 63] = (mem_readb_phys(dev->dac[dac_nr].addr + 3) ^ 0x80) << 8;
|
|
dev->dac[dac_nr].addr += 4;
|
|
|
|
dev->dac[dac_nr].buffer_pos_end += 2;
|
|
dev->dac[dac_nr].count++;
|
|
|
|
if (dev->dac[dac_nr].count > dev->dac[dac_nr].size) {
|
|
dev->dac[dac_nr].count = 0;
|
|
dev->dac[dac_nr].addr = dev->dac[dac_nr].addr_latch;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FORMAT_MONO_16:
|
|
for (c = 0; c < 16; c += 2) {
|
|
dev->dac[dac_nr].buffer_l[(pos + c) & 63] = dev->dac[dac_nr].buffer_r[(pos + c) & 63] = mem_readw_phys(dev->dac[dac_nr].addr);
|
|
dev->dac[dac_nr].buffer_l[(pos + c + 1) & 63] = dev->dac[dac_nr].buffer_r[(pos + c + 1) & 63] = mem_readw_phys(dev->dac[dac_nr].addr + 2);
|
|
dev->dac[dac_nr].addr += 4;
|
|
|
|
dev->dac[dac_nr].buffer_pos_end += 2;
|
|
dev->dac[dac_nr].count++;
|
|
|
|
if (dev->dac[dac_nr].count > dev->dac[dac_nr].size) {
|
|
dev->dac[dac_nr].count = 0;
|
|
dev->dac[dac_nr].addr = dev->dac[dac_nr].addr_latch;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FORMAT_STEREO_16:
|
|
for (c = 0; c < 4; c++) {
|
|
dev->dac[dac_nr].buffer_l[(pos + c) & 63] = mem_readw_phys(dev->dac[dac_nr].addr);
|
|
dev->dac[dac_nr].buffer_r[(pos + c) & 63] = mem_readw_phys(dev->dac[dac_nr].addr + 2);
|
|
dev->dac[dac_nr].addr += 4;
|
|
|
|
dev->dac[dac_nr].buffer_pos_end++;
|
|
dev->dac[dac_nr].count++;
|
|
|
|
if (dev->dac[dac_nr].count > dev->dac[dac_nr].size) {
|
|
dev->dac[dac_nr].count = 0;
|
|
dev->dac[dac_nr].addr = dev->dac[dac_nr].addr_latch;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static inline float
|
|
low_fir_es1371(int dac_nr, int i, float NewSample)
|
|
{
|
|
static float x[2][2][128]; // input samples
|
|
static int x_pos[2] = { 0, 0 };
|
|
float out = 0.0;
|
|
int read_pos, n_coef;
|
|
int pos = x_pos[dac_nr];
|
|
|
|
x[dac_nr][i][pos] = NewSample;
|
|
|
|
/* Since only 1/16th of input samples are non-zero, only filter those that
|
|
are valid.*/
|
|
read_pos = (pos + 15) & (127 & ~15);
|
|
n_coef = (16 - pos) & 15;
|
|
|
|
while (n_coef < ES1371_NCoef) {
|
|
out += low_fir_es1371_coef[n_coef] * x[dac_nr][i][read_pos];
|
|
read_pos = (read_pos + 16) & (127 & ~15);
|
|
n_coef += 16;
|
|
}
|
|
|
|
if (i == 1) {
|
|
x_pos[dac_nr] = (x_pos[dac_nr] + 1) & 127;
|
|
if (x_pos[dac_nr] > 127)
|
|
x_pos[dac_nr] = 0;
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
static void
|
|
es1371_next_sample_filtered(es1371_t *dev, int dac_nr, int out_idx)
|
|
{
|
|
int out_l, out_r;
|
|
int c;
|
|
|
|
if ((dev->dac[dac_nr].buffer_pos - dev->dac[dac_nr].buffer_pos_end) >= 0)
|
|
es1371_fetch(dev, dac_nr);
|
|
|
|
out_l = dev->dac[dac_nr].buffer_l[dev->dac[dac_nr].buffer_pos & 63];
|
|
out_r = dev->dac[dac_nr].buffer_r[dev->dac[dac_nr].buffer_pos & 63];
|
|
|
|
dev->dac[dac_nr].filtered_l[out_idx] = (int) low_fir_es1371(dac_nr, 0, (float) out_l);
|
|
dev->dac[dac_nr].filtered_r[out_idx] = (int) low_fir_es1371(dac_nr, 1, (float) out_r);
|
|
|
|
for (c = 1; c < 16; c++) {
|
|
dev->dac[dac_nr].filtered_l[out_idx + c] = (int) low_fir_es1371(dac_nr, 0, 0);
|
|
dev->dac[dac_nr].filtered_r[out_idx + c] = (int) low_fir_es1371(dac_nr, 1, 0);
|
|
}
|
|
|
|
dev->dac[dac_nr].buffer_pos++;
|
|
}
|
|
|
|
static void
|
|
es1371_update(es1371_t *dev)
|
|
{
|
|
int32_t l, r;
|
|
|
|
l = (dev->dac[0].out_l * dev->dac[0].vol_l) >> 12;
|
|
l += ((dev->dac[1].out_l * dev->dac[1].vol_l) >> 12);
|
|
r = (dev->dac[0].out_r * dev->dac[0].vol_r) >> 12;
|
|
r += ((dev->dac[1].out_r * dev->dac[1].vol_r) >> 12);
|
|
|
|
l >>= 1;
|
|
r >>= 1;
|
|
|
|
l = (((l * dev->pcm_vol_l) >> 15) * dev->master_vol_l) >> 15;
|
|
r = (((r * dev->pcm_vol_r) >> 15) * dev->master_vol_r) >> 15;
|
|
|
|
if (l < -32768)
|
|
l = -32768;
|
|
else if (l > 32767)
|
|
l = 32767;
|
|
if (r < -32768)
|
|
r = -32768;
|
|
else if (r > 32767)
|
|
r = 32767;
|
|
|
|
for (; dev->pos < sound_pos_global; dev->pos++) {
|
|
dev->buffer[dev->pos * 2] = l;
|
|
dev->buffer[dev->pos * 2 + 1] = r;
|
|
}
|
|
}
|
|
|
|
static void
|
|
es1371_poll(void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
int frac, idx, samp1_l, samp1_r, samp2_l, samp2_r;
|
|
|
|
timer_advance_u64(&dev->dac[1].timer, dev->dac[1].latch);
|
|
|
|
es1371_scan_fifo(dev);
|
|
|
|
es1371_update(dev);
|
|
|
|
if (dev->int_ctrl & INT_DAC1_EN) {
|
|
frac = dev->dac[0].ac & 0x7fff;
|
|
idx = dev->dac[0].ac >> 15;
|
|
samp1_l = dev->dac[0].filtered_l[idx];
|
|
samp1_r = dev->dac[0].filtered_r[idx];
|
|
samp2_l = dev->dac[0].filtered_l[(idx + 1) & 31];
|
|
samp2_r = dev->dac[0].filtered_r[(idx + 1) & 31];
|
|
|
|
dev->dac[0].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15;
|
|
dev->dac[0].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15;
|
|
dev->dac[0].ac += dev->dac[0].vf;
|
|
dev->dac[0].ac &= ((32 << 15) - 1);
|
|
if ((dev->dac[0].ac >> (15 + 4)) != dev->dac[0].f_pos) {
|
|
es1371_next_sample_filtered(dev, 0, dev->dac[0].f_pos ? 16 : 0);
|
|
dev->dac[0].f_pos = (dev->dac[0].f_pos + 1) & 1;
|
|
|
|
dev->dac[0].curr_samp_ct--;
|
|
if (dev->dac[0].curr_samp_ct < 0) {
|
|
dev->int_status |= INT_STATUS_DAC1;
|
|
es1371_update_irqs(dev);
|
|
dev->dac[0].curr_samp_ct = dev->dac[0].samp_ct;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dev->int_ctrl & INT_DAC2_EN) {
|
|
frac = dev->dac[1].ac & 0x7fff;
|
|
idx = dev->dac[1].ac >> 15;
|
|
samp1_l = dev->dac[1].filtered_l[idx];
|
|
samp1_r = dev->dac[1].filtered_r[idx];
|
|
samp2_l = dev->dac[1].filtered_l[(idx + 1) & 31];
|
|
samp2_r = dev->dac[1].filtered_r[(idx + 1) & 31];
|
|
|
|
dev->dac[1].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15;
|
|
dev->dac[1].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15;
|
|
dev->dac[1].ac += dev->dac[1].vf;
|
|
dev->dac[1].ac &= ((32 << 15) - 1);
|
|
if ((dev->dac[1].ac >> (15 + 4)) != dev->dac[1].f_pos) {
|
|
es1371_next_sample_filtered(dev, 1, dev->dac[1].f_pos ? 16 : 0);
|
|
dev->dac[1].f_pos = (dev->dac[1].f_pos + 1) & 1;
|
|
|
|
dev->dac[1].curr_samp_ct--;
|
|
if (dev->dac[1].curr_samp_ct < 0) {
|
|
dev->int_status |= INT_STATUS_DAC2;
|
|
es1371_update_irqs(dev);
|
|
dev->dac[1].curr_samp_ct = dev->dac[1].samp_ct;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
es1371_get_buffer(int32_t *buffer, int len, void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
int c;
|
|
|
|
es1371_update(dev);
|
|
|
|
for (c = 0; c < len * 2; c++)
|
|
buffer[c] += (dev->buffer[c] / 2);
|
|
|
|
dev->pos = 0;
|
|
}
|
|
|
|
static void
|
|
es1371_filter_cd_audio(int channel, double *buffer, void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
double c;
|
|
int cd = channel ? dev->cd_vol_r : dev->cd_vol_l;
|
|
int master = channel ? dev->master_vol_r : dev->master_vol_l;
|
|
|
|
c = ((((*buffer) * cd) / 65536.0) * master) / 65536.0;
|
|
*buffer = c;
|
|
}
|
|
|
|
static inline double
|
|
sinc(double x)
|
|
{
|
|
return sin(M_PI * x) / (M_PI * x);
|
|
}
|
|
|
|
static void
|
|
generate_es1371_filter(void)
|
|
{
|
|
/* Cutoff frequency = 1 / 32 */
|
|
float fC = 1.0 / 32.0;
|
|
float gain;
|
|
int n;
|
|
|
|
for (n = 0; n < ES1371_NCoef; n++) {
|
|
/* Blackman window */
|
|
double w = 0.42 - (0.5 * cos((2.0 * n * M_PI) / (double) (ES1371_NCoef - 1))) + (0.08 * cos((4.0 * n * M_PI) / (double) (ES1371_NCoef - 1)));
|
|
/* Sinc filter */
|
|
double h = sinc(2.0 * fC * ((double) n - ((double) (ES1371_NCoef - 1) / 2.0)));
|
|
|
|
/* Create windowed-sinc filter */
|
|
low_fir_es1371_coef[n] = w * h;
|
|
}
|
|
|
|
low_fir_es1371_coef[(ES1371_NCoef - 1) / 2] = 1.0;
|
|
|
|
gain = 0.0;
|
|
for (n = 0; n < ES1371_NCoef; n++)
|
|
gain += low_fir_es1371_coef[n] / (float) N;
|
|
|
|
gain /= 0.95;
|
|
|
|
/* Normalise filter, to produce unity gain */
|
|
for (n = 0; n < ES1371_NCoef; n++)
|
|
low_fir_es1371_coef[n] /= gain;
|
|
}
|
|
|
|
static void
|
|
es1371_input_msg(void *p, uint8_t *msg, uint32_t len)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < len; i++)
|
|
es1371_write_fifo(dev, msg[i]);
|
|
}
|
|
|
|
static int
|
|
es1371_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
uint32_t i = -1;
|
|
|
|
audiopci_log("Abort = %i\n", abort);
|
|
|
|
if (dev->uart_status & UART_STATUS_RXRDY)
|
|
abort = 1;
|
|
|
|
if (!abort) {
|
|
for (i = 0; i < len; i++) {
|
|
es1371_write_fifo(dev, buffer[i]);
|
|
if (dev->uart_status & UART_STATUS_RXRDY)
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* The last sent position is in i. Return 7 - i. */
|
|
|
|
return 7 - i;
|
|
}
|
|
|
|
static void *
|
|
es1371_init(const device_t *info)
|
|
{
|
|
es1371_t *dev = malloc(sizeof(es1371_t));
|
|
memset(dev, 0x00, sizeof(es1371_t));
|
|
|
|
if (device_get_config_int("receive_input"))
|
|
midi_in_handler(1, es1371_input_msg, es1371_input_sysex, dev);
|
|
|
|
sound_add_handler(es1371_get_buffer, dev);
|
|
sound_set_cd_audio_filter(es1371_filter_cd_audio, dev);
|
|
|
|
dev->gameport = gameport_add(&gameport_pnp_device);
|
|
gameport_remap(dev->gameport, 0x200);
|
|
|
|
dev->card = pci_add_card(info->local ? PCI_ADD_SOUND : PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, dev);
|
|
|
|
timer_add(&dev->dac[1].timer, es1371_poll, dev, 1);
|
|
|
|
generate_es1371_filter();
|
|
|
|
ac97_codec = &dev->codec;
|
|
ac97_codec_count = 1;
|
|
ac97_codec_id = 0;
|
|
/* Let the machine decide the codec on onboard implementations. */
|
|
if (!info->local)
|
|
device_add(ac97_codec_get(device_get_config_int("codec")));
|
|
|
|
es1371_reset(dev);
|
|
|
|
return dev;
|
|
}
|
|
|
|
static void
|
|
es1371_close(void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
|
|
free(dev);
|
|
}
|
|
|
|
static void
|
|
es1371_speed_changed(void *p)
|
|
{
|
|
es1371_t *dev = (es1371_t *) p;
|
|
|
|
dev->dac[1].latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / 48000.0));
|
|
}
|
|
|
|
static const device_config_t es1371_config[] = {
|
|
// clang-format off
|
|
{
|
|
.name = "codec",
|
|
.description = "CODEC",
|
|
.type = CONFIG_SELECTION,
|
|
.selection = {
|
|
{
|
|
.description = "Asahi Kasei AK4540",
|
|
.value = AC97_CODEC_AK4540
|
|
}, {
|
|
.description = "Crystal CS4297",
|
|
.value = AC97_CODEC_CS4297
|
|
}, {
|
|
.description = "Crystal CS4297A",
|
|
.value = AC97_CODEC_CS4297A
|
|
}, {
|
|
.description = "SigmaTel STAC9708",
|
|
.value = AC97_CODEC_STAC9708
|
|
}, {
|
|
.description = "SigmaTel STAC9721",
|
|
.value = AC97_CODEC_STAC9721
|
|
}
|
|
},
|
|
.default_int = AC97_CODEC_CS4297A
|
|
},
|
|
{
|
|
"receive_input", "Receive input (MIDI)", CONFIG_BINARY, "", 1
|
|
},
|
|
{
|
|
"", "", -1
|
|
}
|
|
// clang-format on
|
|
};
|
|
|
|
const device_t es1371_device = {
|
|
"Ensoniq AudioPCI (ES1371)",
|
|
"es1371",
|
|
DEVICE_PCI,
|
|
0,
|
|
es1371_init,
|
|
es1371_close,
|
|
es1371_reset,
|
|
{ NULL },
|
|
es1371_speed_changed,
|
|
NULL,
|
|
es1371_config
|
|
};
|
|
|
|
const device_t es1371_onboard_device = {
|
|
"Ensoniq AudioPCI (ES1371) (On-Board)",
|
|
"es1371_onboard",
|
|
DEVICE_PCI,
|
|
1,
|
|
es1371_init,
|
|
es1371_close,
|
|
es1371_reset,
|
|
{ NULL },
|
|
es1371_speed_changed,
|
|
NULL,
|
|
NULL
|
|
};
|