From cbdc3d9688bf000083ab29912b11e9c785cfa7ec Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 19 Jan 2022 12:43:29 +0100 Subject: [PATCH] Implemented ES1371 MIDI input. --- src/sound/snd_audiopci.c | 192 +++++++++++++++++++++++++++++++++------ 1 file changed, 163 insertions(+), 29 deletions(-) diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index 7f10701f5..444108a25 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -70,6 +70,10 @@ typedef struct { uint8_t uart_ctrl, uart_status, uart_res; uint32_t uart_fifo; + + uint8_t midi_queue[64], midi_data; + int midi_r, midi_w; + int uart_in, sysex, valid; ac97_codec_t * codec; uint32_t codec_ctrl; @@ -174,7 +178,6 @@ typedef struct { 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; @@ -201,14 +204,19 @@ 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; + irq = 1; if ((dev->int_status & INT_STATUS_DAC2) && (dev->si_cr & SI_P2_INTR_EN)) - irq = 1; + irq = 1; - /* MIDI input is unsupported for now */ - if ((dev->int_status & INT_STATUS_UART) && (dev->uart_status & UART_STATUS_TXINT) && - ((dev->uart_ctrl & UART_CTRL_TXINTEN) != 0x20)) - irq = 1; + if (dev->int_status & INT_STATUS_UART) { + if (((dev->uart_ctrl & UART_CTRL_TXINTEN) != 0x20) && (dev->uart_status & UART_STATUS_TXINT) && !dev->uart_in) { + audiopci_log("TXINT\n"); + irq = 1; + } else if ((dev->uart_ctrl & UART_CTRL_RXINTEN) && (dev->uart_status & UART_STATUS_RXINT) && (dev->uart_in)) { + audiopci_log("RXINT\n"); + irq = 1; + } + } if (irq) dev->int_status |= INT_STATUS_INTR; @@ -230,6 +238,11 @@ es1371_reset(void *p) { es1371_t *dev = (es1371_t *) p; + dev->uart_in = 0; + dev->midi_r = 0; + dev->midi_w = 0; + dev->valid = 0; + nmi = 0; /* Interrupt/Chip Select Control Register, Address 00H @@ -344,7 +357,10 @@ es1371_read_frame_reg(es1371_t *dev, int frame, int page) /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b Addressable as longword only */ case 0xe: case 0xf: - ret = dev->uart_fifo; + ret = dev->midi_data; + if (dev->valid) { + ret |= 0x100; + } break; } break; @@ -363,7 +379,10 @@ es1371_read_frame_reg(es1371_t *dev, int frame, int page) /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b Addressable as longword only */ case 0xe: case 0xf: - ret = dev->uart_fifo; + ret = dev->midi_data; + if (dev->valid) { + ret |= 0x100; + } break; } break; @@ -377,7 +396,10 @@ es1371_read_frame_reg(es1371_t *dev, int frame, int page) /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b Addressable as longword only */ case 0xe: case 0xf: - ret = dev->uart_fifo; + ret = dev->midi_data; + if (dev->valid) { + ret |= 0x100; + } break; } break; @@ -391,12 +413,19 @@ es1371_read_frame_reg(es1371_t *dev, int frame, int page) /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b Addressable as longword only */ case 0xe: case 0xf: - ret = dev->uart_fifo; + ret = dev->midi_data; + if (dev->valid) { + ret |= 0x100; + } 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; } @@ -419,7 +448,8 @@ es1371_write_frame_reg(es1371_t *dev, int frame, int page, uint32_t val) break; /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b Addressable as longword only */ - case 0xe: case 0xf: + case 0xe: + case 0xf: dev->uart_fifo = (dev->uart_fifo & 0xfffffe00) | (val & 0x000001ff); break; } @@ -440,7 +470,8 @@ es1371_write_frame_reg(es1371_t *dev, int frame, int page, uint32_t val) break; /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b Addressable as longword only */ - case 0xe: case 0xf: + case 0xe: + case 0xf: dev->uart_fifo = (dev->uart_fifo & 0xfffffe00) | (val & 0x000001ff); break; } @@ -454,7 +485,8 @@ es1371_write_frame_reg(es1371_t *dev, int frame, int page, uint32_t val) break; /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b Addressable as longword only */ - case 0xe: case 0xf: + case 0xe: + case 0xf: dev->uart_fifo = (dev->uart_fifo & 0xfffffe00) | (val & 0x000001ff); break; } @@ -469,12 +501,18 @@ es1371_write_frame_reg(es1371_t *dev, int frame, int page, uint32_t val) break; /* UART FIFO Register, Address 30H, 34H, 38H, 3CH, Memory Page 1110b, 1111b Addressable as longword only */ - case 0xe: case 0xf: + case 0xe: + case 0xf: dev->uart_fifo = (dev->uart_fifo & 0xfffffe00) | (val & 0x000001ff); 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); + dev->valid = 0; + } } @@ -520,6 +558,19 @@ es1371_inb(uint16_t port, void *p) Addressable as byte only */ case 0x08: ret = 0x00; + if (dev->uart_in) { + ret = dev->midi_queue[dev->midi_r]; + if (dev->midi_r != dev->midi_w) { + dev->midi_r++; + dev->midi_r &= 0x3f; + } + dev->midi_data = ret; + audiopci_log("MIDI input ret = %02x, pos = %i, valid = %i\n", ret, dev->midi_r, dev->valid); + if (!dev->valid) + dev->int_status &= ~INT_STATUS_UART; + dev->uart_status &= ~(UART_STATUS_RXINT | UART_STATUS_RXRDY); + es1371_update_irqs(dev); + } break; /* UART Status Register, Address 09H @@ -661,6 +712,8 @@ es1371_inw(uint16_t port, void *p) break; } + audiopci_log("es1371_inw: port=%04x ret=%04x\n", port, ret); + return ret; } @@ -783,6 +836,7 @@ es1371_outb(uint16_t port, uint8_t val, void *p) /* UART Data Register, Address 08H Addressable as byte only */ case 0x08: + audiopci_log("MIDI data = %02x\n", dev->midi_data); midi_raw_out_byte(val); break; @@ -790,10 +844,22 @@ es1371_outb(uint16_t port, uint8_t val, void *p) Addressable as byte only */ case 0x09: dev->uart_ctrl = val & 0xe3; - if ((dev->uart_ctrl & UART_CTRL_TXINTEN) != 0x20) + + if ((val & 0x03) == 0x03) { /*Software reset*/ + dev->uart_in = 0; + dev->uart_status = 0x00; + dev->midi_r = 0; + dev->midi_w = 0; + dev->valid = 0; + } else if (dev->uart_ctrl & UART_CTRL_RXINTEN) { + dev->uart_in = 1; + audiopci_log("ES1371 UART RX Cntrl = %02x\n", dev->uart_ctrl); + } else if ((dev->uart_ctrl & UART_CTRL_TXINTEN) != 0x20) { dev->int_status &= ~INT_STATUS_UART; + dev->uart_in = 0; + } + es1371_update_irqs(dev); - audiopci_log("ES1371 UART Cntrl = %02x\n", dev->uart_ctrl); break; /* UART Reserved Register, Address 0AH @@ -1708,19 +1774,32 @@ es1371_poll(void *p) if (dev->int_ctrl & INT_UART_EN) { //audiopci_log("UART INT Enabled\n"); - if (dev->uart_ctrl & UART_CTRL_RXINTEN) { - /* We currently don't implement MIDI Input. - But if anything sets MIDI Input and Output together we'd have to take account - of the MIDI Output case, and disable IRQ's and RX bits when MIDI Input is - enabled as well but not in the MIDI Output portion */ - dev->int_status &= ~INT_STATUS_UART; - dev->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); - } else if (!(dev->uart_ctrl & UART_CTRL_RXINTEN) && ((dev->uart_ctrl & UART_CTRL_TXINTEN))) { - /* Or enable the UART IRQ and the respective TX bits only when the MIDI Output is - enabled */ + if (((dev->uart_ctrl & (UART_CTRL_RXINTEN | UART_CTRL_TXINTEN)) == UART_CTRL_RXINTEN) && dev->uart_in) { + audiopci_log("RX irq\n"); dev->int_status |= INT_STATUS_UART; + } else if (((dev->uart_ctrl & (UART_CTRL_RXINTEN | UART_CTRL_TXINTEN)) == UART_CTRL_TXINTEN) && !dev->uart_in) { + audiopci_log("TX irq\n"); + dev->int_status |= INT_STATUS_UART; + } else if ((dev->uart_ctrl & (UART_CTRL_RXINTEN | UART_CTRL_TXINTEN)) == (UART_CTRL_RXINTEN | UART_CTRL_TXINTEN)) { + dev->int_status &= ~INT_STATUS_UART; + if (dev->uart_in) { + audiopci_log("No Status UART RX\n"); + dev->uart_status |= (UART_STATUS_RXINT | UART_STATUS_RXRDY); + dev->uart_status &= ~(UART_STATUS_TXINT | UART_STATUS_TXRDY); + } else { + audiopci_log("No Status UART TX\n"); + dev->uart_status &= ~(UART_STATUS_RXINT | UART_STATUS_RXRDY); + dev->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); + } } else { - dev->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); + audiopci_log("STAT UART IN = %i\n", dev->uart_in); + if (dev->uart_in) { + dev->uart_status |= (UART_STATUS_RXINT | UART_STATUS_RXRDY); + dev->uart_status &= ~(UART_STATUS_TXINT | UART_STATUS_TXRDY); + } else { + dev->uart_status &= ~(UART_STATUS_RXINT | UART_STATUS_RXRDY); + dev->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); + } } //audiopci_log("UART control = %02x\n", dev->uart_ctrl & (UART_CTRL_RXINTEN | UART_CTRL_TXINTEN)); @@ -1846,12 +1925,63 @@ generate_es1371_filter(void) } +static void +es1371_input_msg(void *p, uint8_t *msg, uint32_t len) +{ + es1371_t *dev = (es1371_t *)p; + uint8_t i; + + audiopci_log("SYSEX on MSG = %i, len = %i, midiw = %i\n", dev->sysex, len, dev->midi_w); + + if (dev->sysex) + return; + + if (dev->uart_in) { + audiopci_log("RX midi data\n"); + dev->uart_status |= (UART_STATUS_RXINT | UART_STATUS_RXRDY); + dev->valid = 1; + + for (i=0; i < len; i++) { + dev->midi_queue[dev->midi_w++] = msg[i]; + dev->midi_w &= 0x3f; + } + + es1371_update_irqs(dev); + } +} + +static int +es1371_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) +{ + es1371_t *dev = (es1371_t *)p; + uint32_t i; + + audiopci_log("SYSEX = %i, Abort = %i\n", dev->sysex, abort); + + if (abort) { + dev->sysex = 0; + return 0; + } + dev->sysex = 1; + for (i=0;imidi_r == dev->midi_w) + return (len-i); + dev->midi_queue[dev->midi_w++] = buffer[i]; + dev->midi_w &= 0x3f; + } + dev->sysex = 0; + return 0; +} + 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); @@ -1920,7 +2050,11 @@ static const device_config_t es1371_config[] = } }, .default_int = AC97_CODEC_CS4297A - }, { + }, + { + "receive_input", "Receive input (MIDI)", CONFIG_BINARY, "", 1 + }, + { "", "", -1 } };