#include "ibm.h" #include "fdc.h" #include "fdd.h" #include "io.h" #include "lpt.h" #include "serial.h" #include "fdc37c93x.h" typedef struct fdc37c93x_t { int index; uint8_t global_regs[0x30]; uint8_t fdc_regs[0x100]; uint8_t ide1_regs[0x100]; uint8_t ide2_regs[0x100]; uint8_t lpt_regs[0x100]; uint8_t com1_regs[0x100]; uint8_t com2_regs[0x100]; uint8_t rtc_regs[0x100]; uint8_t kbd_regs[0x100]; uint8_t auxio_regs[0x100]; uint8_t accessbus_regs[0x100]; uint8_t lock[2]; } fdc37c93x_t; static fdc37c93x_t fdc37c93x_global; static void write_lock(fdc37c93x_t *fdc37c93x, uint8_t val) { if (val == 0x55 && fdc37c93x->lock[1] == 0x55) fdc_3f1_enable(0); if (fdc37c93x->lock[0] == 0x55 && fdc37c93x->lock[1] == 0x55 && val != 0x55) fdc_3f1_enable(1); fdc37c93x->lock[0] = fdc37c93x->lock[1]; fdc37c93x->lock[1] = val; } void fdc37c93x_write(uint16_t port, uint8_t val, void *p) { fdc37c93x_t *fdc37c93x = (fdc37c93x_t *)p; // pclog("Write SuperIO %04x %02x\n", port, val); if (fdc37c93x->lock[0] == 0x55 && fdc37c93x->lock[1] == 0x55) { if (port == 0x3f0) { if (val == 0xaa) write_lock(fdc37c93x, val); else fdc37c93x->index = val; } else { uint16_t addr; int irq; // pclog("fdc37c93x_write: index=%02x dev=%i val=%02x\n", fdc37c93x->index, fdc37c93x->global_regs[7], val); if (fdc37c93x->index < 0x30) { if (fdc37c93x->index != 0x20 && fdc37c93x->index != 0x21) fdc37c93x->global_regs[fdc37c93x->index] = val; } else switch (fdc37c93x->global_regs[7]) { case 0: fdc37c93x->fdc_regs[fdc37c93x->index] = val; break; case 1: fdc37c93x->ide1_regs[fdc37c93x->index] = val; break; case 2: fdc37c93x->ide2_regs[fdc37c93x->index] = val; break; case 3: fdc37c93x->lpt_regs[fdc37c93x->index] = val; break; case 4: fdc37c93x->com1_regs[fdc37c93x->index] = val; break; case 5: fdc37c93x->com2_regs[fdc37c93x->index] = val; break; case 6: fdc37c93x->rtc_regs[fdc37c93x->index] = val; break; case 7: fdc37c93x->kbd_regs[fdc37c93x->index] = val; break; case 8: fdc37c93x->auxio_regs[fdc37c93x->index] = val; break; case 9: fdc37c93x->accessbus_regs[fdc37c93x->index] = val; break; } fdc_remove(); if ((fdc37c93x->global_regs[0x22] & 0x01) && (fdc37c93x->fdc_regs[0x30] & 0x01)) { // pclog("FDC enabled\n"); fdc_add(); } /* else pclog("FDC disabled\n");*/ lpt1_remove(); lpt2_remove(); addr = (fdc37c93x->lpt_regs[0x61] & 0xfc) | ((fdc37c93x->lpt_regs[0x60] & 3) << 8); if ((fdc37c93x->global_regs[0x22] & (1 << 3)) && (fdc37c93x->lpt_regs[0x30] & 0x01)) { // pclog("LPT addr = %04x\n", addr); lpt1_init(addr); } /* else pclog("LPT disabled\n");*/ serial1_remove(); addr = (fdc37c93x->com1_regs[0x61] & 0xf8) | ((fdc37c93x->com1_regs[0x60] & 3) << 8); irq = fdc37c93x->com1_regs[0x70] & 0xf; if ((fdc37c93x->global_regs[0x22] & (1 << 4)) && (fdc37c93x->com1_regs[0x30] & 0x01)) { // pclog("COM1 addr = %04x, IRQ = %i\n", addr, irq); serial1_set(addr, irq); } /* else pclog("COM1 disabled\n");*/ serial2_remove(); addr = (fdc37c93x->com2_regs[0x61] & 0xf8) | ((fdc37c93x->com2_regs[0x60] & 3) << 8); irq = fdc37c93x->com2_regs[0x70] & 0xf; if ((fdc37c93x->global_regs[0x22] & (1 << 5)) && (fdc37c93x->com2_regs[0x30] & 0x01)) { // pclog("COM2 addr = %04x, IRQ = %i\n", addr, irq); serial2_set(addr, irq); } /* else pclog("COM2 disabled\n");*/ fdc_update_enh_mode(fdc37c93x->fdc_regs[0xf0] & 1); fdc_update_densel_force((fdc37c93x->fdc_regs[0xf1] & 0x0c) >> 2); fdd_swap = (fdc37c93x->fdc_regs[0xf0] & (1 << 4)) ? 1 : 0; } } else { if (port == 0x3f0) write_lock(fdc37c93x, val); } } uint8_t fdc37c93x_read(uint16_t port, void *p) { fdc37c93x_t *fdc37c93x = (fdc37c93x_t *)p; // pclog("Read SuperIO %04x %02x\n", port, fdc37c665_curreg); if (fdc37c93x->lock[0] == 0x55 && fdc37c93x->lock[1] == 0x55) { if (port == 0x3f1) { if (fdc37c93x->index < 0x30) return fdc37c93x->global_regs[fdc37c93x->index]; else switch (fdc37c93x->global_regs[7]) { case 0: return fdc37c93x->fdc_regs[fdc37c93x->index]; case 1: return fdc37c93x->ide1_regs[fdc37c93x->index]; case 2: return fdc37c93x->ide2_regs[fdc37c93x->index]; case 3: return fdc37c93x->lpt_regs[fdc37c93x->index]; case 4: return fdc37c93x->com1_regs[fdc37c93x->index]; case 5: return fdc37c93x->com2_regs[fdc37c93x->index]; case 6: return fdc37c93x->rtc_regs[fdc37c93x->index]; case 7: return fdc37c93x->kbd_regs[fdc37c93x->index]; case 8: return fdc37c93x->auxio_regs[fdc37c93x->index]; case 9: return fdc37c93x->accessbus_regs[fdc37c93x->index]; } } } return 0xff; } void fdc37c932fr_init() { fdc37c93x_t *fdc37c93x = &fdc37c93x_global; int c; io_sethandler(0x03f0, 0x0002, fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, fdc37c93x); fdc_update_is_nsc(0); memset(&fdc37c93x_global, 0, sizeof(fdc37c93x_global)); fdc37c93x->global_regs[0x03] = 0x03; fdc37c93x->global_regs[0x20] = 0x03; fdc37c93x->global_regs[0x21] = 0x01; fdc37c93x->global_regs[0x24] = 0x04; fdc37c93x->global_regs[0x26] = 0xf0; fdc37c93x->global_regs[0x27] = 0x03; fdc37c93x->fdc_regs[0x60] = 0x03; fdc37c93x->fdc_regs[0x61] = 0xf0; fdc37c93x->fdc_regs[0x70] = 0x06; fdc37c93x->fdc_regs[0x74] = 0x02; fdc37c93x->fdc_regs[0xf0] = 0x0e; fdc37c93x->fdc_regs[0xf2] = 0xff; fdc37c93x->ide1_regs[0x60] = 0x01; fdc37c93x->ide1_regs[0x61] = 0xf0; fdc37c93x->ide1_regs[0x62] = 0x03; fdc37c93x->ide1_regs[0x63] = 0xf6; fdc37c93x->ide1_regs[0x70] = 0x0e; fdc37c93x->ide1_regs[0xf0] = 0x0c; fdc37c93x->ide1_regs[0xf1] = 0x0d; fdc37c93x->lpt_regs[0x74] = 0x04; fdc37c93x->lpt_regs[0xf0] = 0x3c; fdc37c93x->com2_regs[0x74] = 0x04; fdc37c93x->com2_regs[0xf1] = 0x02; fdc37c93x->com2_regs[0xf2] = 0x03; fdc37c93x->rtc_regs[0x63] = 0x70; fdc37c93x->rtc_regs[0xf4] = 0x03; fdc37c93x->auxio_regs[0xb1] = 0x80; fdc37c93x->auxio_regs[0xc0] = 0x01; fdc37c93x->auxio_regs[0xc1] = 0x01; fdc37c93x->auxio_regs[0xc5] = 0x01; fdc37c93x->auxio_regs[0xc6] = 0x01; fdc37c93x->auxio_regs[0xc7] = 0x01; fdc37c93x->auxio_regs[0xc8] = 0x01; fdc37c93x->auxio_regs[0xc9] = 0x80; for (c = 0xcb; c < 0xee; c++) fdc37c93x->auxio_regs[c] = 0x01; fdc_update_densel_polarity(1); fdc_update_densel_force(0); fdd_swap = 0; }