#include "ibm.h" #include "io.h" #include "pic.h" #include "plat-midi.h" #include "sound_mpu401_uart.h" enum { STATUS_OUTPUT_NOT_READY = 0x40, STATUS_INPUT_NOT_READY = 0x80 }; static void mpu401_uart_raise_irq(void *p) { mpu401_uart_t *mpu = (mpu401_uart_t *)p; if (mpu->irq != -1) picint(1 << mpu->irq); } static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p) { mpu401_uart_t *mpu = (mpu401_uart_t *)p; if (addr & 1) /*Command*/ { switch (val) { case 0xff: /*Reset*/ // From Roland: "An ACK will not be sent back upon sending a SYSTEM RESET to leave the UART MODE ($3F)." // But actual behaviour is weird. For example, the MPU401 port test in the AZT1605 drivers for Windows NT // want this to return an Ack but the IRQ test in the same driver wants this to raise no interrupts! mpu->rx_data = 0xfe; /*Acknowledge*/ mpu->uart_mode = 0; if (mpu->is_aztech) mpu->status = STATUS_OUTPUT_NOT_READY; else { mpu->status = 0; mpu401_uart_raise_irq(p); } break; case 0x3f: /*Enter UART mode*/ mpu->rx_data = 0xfe; /*Acknowledge*/ mpu->uart_mode = 1; if (mpu->is_aztech) { mpu->status = STATUS_OUTPUT_NOT_READY; mpu401_uart_raise_irq(p); } else mpu->status = 0; break; } return; } /*Data*/ if (mpu->uart_mode) midi_write(val); } static uint8_t mpu401_uart_read(uint16_t addr, void *p) { mpu401_uart_t *mpu = (mpu401_uart_t *)p; if (addr & 1) /*Status*/ return mpu->status; /*Data*/ mpu->status = STATUS_INPUT_NOT_READY; return mpu->rx_data; } void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr, int irq, int is_aztech) { mpu->status = STATUS_INPUT_NOT_READY; mpu->uart_mode = 0; mpu->addr = addr; mpu->irq = irq; mpu->is_aztech = is_aztech; io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); } void mpu401_uart_update_addr(mpu401_uart_t *mpu, uint16_t addr) { io_removehandler(mpu->addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); mpu->addr = addr; if (addr != 0) io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); } void mpu401_uart_update_irq(mpu401_uart_t *mpu, int irq) { mpu->irq = irq; }