diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index 1786a9569..3b90f72c8 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -21,6 +21,7 @@ extern void vt82c686_sio_write(uint8_t addr, uint8_t val, void *priv); extern const device_t acc3221_device; extern const device_t f82c710_device; extern const device_t fdc37c651_device; +extern const device_t fdc37c651_ide_device; extern const device_t fdc37c661_device; extern const device_t fdc37c663_device; extern const device_t fdc37c663_ide_device; diff --git a/src/sio/sio_fdc37c651.c b/src/sio/sio_fdc37c651.c index 2bfd3fd93..a19460d4c 100644 --- a/src/sio/sio_fdc37c651.c +++ b/src/sio/sio_fdc37c651.c @@ -6,10 +6,11 @@ * * This file is part of the 86Box distribution. * - * Emulation of the SMC FDC37C651 Super I/O + * Implementation of the SMC FDC37C651 Super I/O Chip. * - * Authors: Tiseno100 - * Copyright 2020 Tiseno100 + * Authors: Miran Grca, + * + * Copyright 2021 Miran Grca. */ #include #include @@ -30,15 +31,17 @@ #include <86box/fdc.h> #include <86box/sio.h> + #ifdef ENABLE_FDC37C651_LOG int fdc37c651_do_log = ENABLE_FDC37C651_LOG; + + static void fdc37c651_log(const char *fmt, ...) { va_list ap; - if (fdc37c651_do_log) - { + if (fdc37c651_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); @@ -48,143 +51,264 @@ fdc37c651_log(const char *fmt, ...) #define fdc37c651_log(fmt, ...) #endif -typedef struct -{ - uint8_t configuration_select, regs[3]; - uint16_t com3, com4; - fdc_t *fdc_controller; +typedef struct { + uint8_t tries, has_ide, + regs[16]; + int cur_reg, + com3_addr, com4_addr; + fdc_t *fdc; serial_t *uart[2]; - } fdc37c651_t; + static void -fdc37c651_write(uint16_t addr, uint8_t val, void *priv) +set_com34_addr(fdc37c651_t *dev) { - fdc37c651_t *dev = (fdc37c651_t *)priv; - - switch (addr) - { - case 0x3f0: - dev->configuration_select = val; - break; - case 0x3f1: - switch (dev->configuration_select) - { - case 0: /* CR0 */ - dev->regs[dev->configuration_select] = val; - ide_pri_disable(); - fdc_remove(dev->fdc_controller); - - if (val & 1) /* Enable IDE */ - ide_pri_enable(); - - if (val & 0x10) /* Enable FDC */ - fdc_set_base(dev->fdc_controller, 0x3f0); - - break; - - case 1: /* CR1 */ - dev->regs[dev->configuration_select] = val; - lpt1_remove(); - - if ((val & 3) != 0) /* Program LPT if not Disabled */ - lpt1_init((val & 2) ? ((val & 1) ? 0x278 : 0x378) : 0x3f8); - - switch ((val >> 4) & 3) /* COM3 & 4 Select*/ - { - case 0: - dev->com3 = 0x338; - dev->com4 = 0x238; - break; - case 1: - dev->com3 = 0x3e8; - dev->com4 = 0x2e8; - break; - case 2: - dev->com3 = 0x2e8; - dev->com4 = 0x2e0; - break; - case 3: - dev->com3 = 0x220; - dev->com4 = 0x228; - break; - } - - break; - - case 2: /* CR2 */ - dev->regs[dev->configuration_select] = val; - serial_remove(dev->uart[0]); - serial_remove(dev->uart[1]); - - if (val & 4) - serial_setup(dev->uart[0], (val & 2) ? ((val & 1) ? dev->com4 : dev->com3) : ((val & 1) ? 0x2f8 : 0x3f8), 4); - - if (val & 0x40) - serial_setup(dev->uart[1], (val & 0x20) ? ((val & 0x10) ? dev->com4 : dev->com3) : ((val & 0x10) ? 0x2f8 : 0x3f8), 3); - - break; - } - break; + switch (dev->regs[1] & 0x60) { + case 0x00: + dev->com3_addr = 0x338; + dev->com4_addr = 0x238; + break; + case 0x20: + dev->com3_addr = 0x3e8; + dev->com4_addr = 0x2e8; + break; + case 0x40: + dev->com3_addr = 0x3e8; + dev->com4_addr = 0x2e0; + break; + case 0x60: + dev->com3_addr = 0x220; + dev->com4_addr = 0x228; + break; } } -static uint8_t -fdc37c651_read(uint16_t addr, void *priv) -{ - fdc37c651_t *dev = (fdc37c651_t *)priv; - return dev->regs[dev->configuration_select]; +static void +set_serial_addr(fdc37c651_t *dev, int port) +{ + uint8_t shift = (port << 2); + + serial_remove(dev->uart[port]); + if (dev->regs[2] & (4 << shift)) { + switch ((dev->regs[2] >> shift) & 3) { + case 0: + serial_setup(dev->uart[port], SERIAL1_ADDR, SERIAL1_IRQ); + break; + case 1: + serial_setup(dev->uart[port], SERIAL2_ADDR, SERIAL2_IRQ); + break; + case 2: + serial_setup(dev->uart[port], dev->com3_addr, 4); + break; + case 3: + serial_setup(dev->uart[port], dev->com4_addr, 3); + break; + } + } } + +static void +lpt1_handler(fdc37c651_t *dev) +{ + lpt1_remove(); + switch (dev->regs[1] & 3) { + case 1: + lpt1_init(0x3bc); + lpt1_irq(7); + break; + case 2: + lpt1_init(0x378); + lpt1_irq(7 /*5*/); + break; + case 3: + lpt1_init(0x278); + lpt1_irq(7 /*5*/); + break; + } +} + + +static void +fdc_handler(fdc37c651_t *dev) +{ + fdc_remove(dev->fdc); + if (dev->regs[0] & 0x10) + fdc_set_base(dev->fdc, 0x03f0); +} + + + +static void +ide_handler(fdc37c651_t *dev) +{ + /* TODO: Make an ide_disable(channel) and ide_enable(channel) so we can simplify this. */ + if (dev->has_ide == 2) { + ide_sec_disable(); + ide_set_base(1, 0x1f0); + ide_set_side(1, 0x3f6); + if (dev->regs[0x00] & 0x01) + ide_sec_enable(); + } else if (dev->has_ide == 1) { + ide_pri_disable(); + ide_set_base(0, 0x1f0); + ide_set_side(0, 0x3f6); + if (dev->regs[0x00] & 0x01) + ide_pri_enable(); + } +} + + +static void +fdc37c651_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c651_t *dev = (fdc37c651_t *) priv; + uint8_t valxor = 0; + + if (dev->tries == 2) { + if (port == 0x3f0) { + if (val == 0xaa) + dev->tries = 0; + else + dev->cur_reg = val; + } else { + if (dev->cur_reg > 15) + return; + + valxor = val ^ dev->regs[dev->cur_reg]; + dev->regs[dev->cur_reg] = val; + + switch(dev->cur_reg) { + case 0: + if (dev->has_ide && (valxor & 0x01)) + ide_handler(dev); + if (valxor & 0x10) + fdc_handler(dev); + break; + case 1: + if (valxor & 3) + lpt1_handler(dev); + if (valxor & 0x60) { + set_com34_addr(dev); + set_serial_addr(dev, 0); + set_serial_addr(dev, 1); + } + break; + case 2: + if (valxor & 7) + set_serial_addr(dev, 0); + if (valxor & 0x70) + set_serial_addr(dev, 1); + break; + } + } + } else if ((port == 0x3f0) && (val == 0x55)) + dev->tries++; +} + + +static uint8_t +fdc37c651_read(uint16_t port, void *priv) +{ + fdc37c651_t *dev = (fdc37c651_t *) priv; + uint8_t ret = 0x00; + + if (dev->tries == 2) { + if (port == 0x3f1) + ret = dev->regs[dev->cur_reg]; + } + + return ret; +} + + +static void +fdc37c651_reset(fdc37c651_t *dev) +{ + dev->com3_addr = 0x338; + dev->com4_addr = 0x238; + + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + + serial_remove(dev->uart[1]); + serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); + + lpt1_remove(); + lpt1_init(0x378); + + fdc_reset(dev->fdc); + fdc_remove(dev->fdc); + + dev->tries = 0; + memset(dev->regs, 0, 16); + + dev->regs[0x0] = 0x3f; + dev->regs[0x1] = 0x9f; + dev->regs[0x2] = 0xdc; + + set_serial_addr(dev, 0); + set_serial_addr(dev, 1); + + lpt1_handler(dev); + + fdc_handler(dev); + + if (dev->has_ide) + ide_handler(dev); +} + + static void fdc37c651_close(void *priv) { - fdc37c651_t *dev = (fdc37c651_t *)priv; + fdc37c651_t *dev = (fdc37c651_t *) priv; + free(dev); } + static void * fdc37c651_init(const device_t *info) { - fdc37c651_t *dev = (fdc37c651_t *)malloc(sizeof(fdc37c651_t)); + fdc37c651_t *dev = (fdc37c651_t *) malloc(sizeof(fdc37c651_t)); memset(dev, 0, sizeof(fdc37c651_t)); - dev->fdc_controller = device_add(&fdc_at_smc_device); + dev->fdc = device_add(&fdc_at_smc_device); + dev->uart[0] = device_add_inst(&ns16450_device, 1); dev->uart[1] = device_add_inst(&ns16450_device, 2); - device_add(&ide_isa_device); - /* Program Defaults */ - dev->regs[0] = 0x3f; - dev->regs[1] = 0x9f; - dev->regs[2] = 0xdc; - ide_pri_disable(); - fdc_remove(dev->fdc_controller); - lpt1_remove(); - serial_remove(dev->uart[0]); - serial_remove(dev->uart[1]); + dev->has_ide = (info->local >> 8) & 0xff; - ide_pri_enable(); - fdc_set_base(dev->fdc_controller, 0x3f0); - lpt1_init(0x278); - serial_setup(dev->uart[0], 0x2f8, 4); - serial_setup(dev->uart[1], 0x3f8, 3); + io_sethandler(0x03f0, 0x0002, + fdc37c651_read, NULL, NULL, fdc37c651_write, NULL, NULL, dev); - io_sethandler(0x03f0, 2, fdc37c651_read, NULL, NULL, fdc37c651_write, NULL, NULL, dev); + fdc37c651_reset(dev); return dev; } + +/* The three appear to differ only in the chip ID, if I + understood their datasheets correctly. */ const device_t fdc37c651_device = { - "SMC FDC37C651", + "SMC FDC37C651 Super I/O", 0, 0, - fdc37c651_init, - fdc37c651_close, - NULL, - {NULL}, - NULL, - NULL, - NULL}; + fdc37c651_init, fdc37c651_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + +const device_t fdc37c651_ide_device = { + "SMC FDC37C651 Super I/O (With IDE)", + 0, + 0x100, + fdc37c651_init, fdc37c651_close, NULL, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/sio/sio_fdc37c661.c b/src/sio/sio_fdc37c661.c index 159a68d47..8a17053a6 100644 --- a/src/sio/sio_fdc37c661.c +++ b/src/sio/sio_fdc37c661.c @@ -6,8 +6,7 @@ * * This file is part of the 86Box distribution. * - * Implementation of the SMC FDC37C661 Super - * I/O Chip. + * Implementation of the SMC FDC37C661 Super I/O Chip. * * * @@ -16,7 +15,6 @@ * * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2020 Miran Grca. - * Copyright 2020 plant/nerd73. */ #include #include @@ -38,8 +36,8 @@ typedef struct { - uint8_t lock[2], - regs[4]; + uint8_t chip_id, tries, + has_ide, regs[16]; int cur_reg, com3_addr, com4_addr; fdc_t *fdc; @@ -47,19 +45,6 @@ typedef struct { } fdc37c661_t; -static void -write_lock(fdc37c661_t *dev, uint8_t val) -{ - if (val == 0x55 && dev->lock[1] == 0x55) - fdc_3f1_enable(dev->fdc, 0); - if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55) && (val != 0x55)) - fdc_3f1_enable(dev->fdc, 1); - - dev->lock[0] = dev->lock[1]; - dev->lock[1] = val; -} - - static void set_com34_addr(fdc37c661_t *dev) { @@ -87,10 +72,11 @@ set_com34_addr(fdc37c661_t *dev) static void set_serial_addr(fdc37c661_t *dev, int port) { - uint8_t shift = (port << 4); + uint8_t shift = (port << 2); + serial_remove(dev->uart[port]); if (dev->regs[2] & (4 << shift)) { - switch (dev->regs[2] & (3 << shift)) { + switch ((dev->regs[2] >> shift) & 3) { case 0: serial_setup(dev->uart[port], SERIAL1_ADDR, SERIAL1_IRQ); break; @@ -119,11 +105,11 @@ lpt1_handler(fdc37c661_t *dev) break; case 2: lpt1_init(0x378); - lpt1_irq(5); + lpt1_irq(7 /*5*/); break; case 3: lpt1_init(0x278); - lpt1_irq(5); + lpt1_irq(7 /*5*/); break; } } @@ -134,7 +120,28 @@ fdc_handler(fdc37c661_t *dev) { fdc_remove(dev->fdc); if (dev->regs[0] & 0x10) - fdc_set_base(dev->fdc, 0x03f0); + fdc_set_base(dev->fdc, 0x03f0); +} + + + +static void +ide_handler(fdc37c661_t *dev) +{ + /* TODO: Make an ide_disable(channel) and ide_enable(channel) so we can simplify this. */ + if (dev->has_ide == 2) { + ide_sec_disable(); + ide_set_base(1, 0x1f0); + ide_set_side(1, 0x3f6); + if (dev->regs[0x00] & 0x01) + ide_sec_enable(); + } else if (dev->has_ide == 1) { + ide_pri_disable(); + ide_set_base(0, 0x1f0); + ide_set_side(0, 0x3f6); + if (dev->regs[0x00] & 0x01) + ide_pri_enable(); + } } @@ -144,14 +151,14 @@ fdc37c661_write(uint16_t port, uint8_t val, void *priv) fdc37c661_t *dev = (fdc37c661_t *) priv; uint8_t valxor = 0; - if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55)) { + if (dev->tries == 2) { if (port == 0x3f0) { if (val == 0xaa) - write_lock(dev, val); + dev->tries = 0; else dev->cur_reg = val; } else { - if (dev->cur_reg > 4) + if (dev->cur_reg > 15) return; valxor = val ^ dev->regs[dev->cur_reg]; @@ -159,6 +166,8 @@ fdc37c661_write(uint16_t port, uint8_t val, void *priv) switch(dev->cur_reg) { case 0: + if (dev->has_ide && (valxor & 0x01)) + ide_handler(dev); if (valxor & 0x10) fdc_handler(dev); break; @@ -166,33 +175,21 @@ fdc37c661_write(uint16_t port, uint8_t val, void *priv) if (valxor & 3) lpt1_handler(dev); if (valxor & 0x60) { - serial_remove(dev->uart[0]); - serial_remove(dev->uart[1]); set_com34_addr(dev); set_serial_addr(dev, 0); set_serial_addr(dev, 1); } break; case 2: - if (valxor & 7) { - serial_remove(dev->uart[0]); + if (valxor & 7) set_serial_addr(dev, 0); - } - if (valxor & 0x70) { - serial_remove(dev->uart[1]); + if (valxor & 0x70) set_serial_addr(dev, 1); - } - break; - case 3: - if (valxor & 4) - fdc_update_enh_mode(dev->fdc, (dev->regs[3] & 4) ? 1 : 0); break; } } - } else { - if (port == 0x3f0) - write_lock(dev, val); - } + } else if ((port == 0x3f0) && (val == 0x55)) + dev->tries++; } @@ -200,9 +197,9 @@ static uint8_t fdc37c661_read(uint16_t port, void *priv) { fdc37c661_t *dev = (fdc37c661_t *) priv; - uint8_t ret = 0xff; + uint8_t ret = 0x00; - if ((dev->lock[0] == 0x55) && (dev->lock[1] == 0x55)) { + if (dev->tries == 2) { if (port == 0x3f1) ret = dev->regs[dev->cur_reg]; } @@ -227,14 +224,25 @@ fdc37c661_reset(fdc37c661_t *dev) lpt1_init(0x378); fdc_reset(dev->fdc); + fdc_remove(dev->fdc); - memset(dev->lock, 0, 2); + dev->tries = 0; memset(dev->regs, 0, 16); dev->regs[0x0] = 0x3f; dev->regs[0x1] = 0x9f; dev->regs[0x2] = 0xdc; dev->regs[0x3] = 0x78; + + set_serial_addr(dev, 0); + set_serial_addr(dev, 1); + + lpt1_handler(dev); + + fdc_handler(dev); + + if (dev->has_ide) + ide_handler(dev); } @@ -255,23 +263,37 @@ fdc37c661_init(const device_t *info) dev->fdc = device_add(&fdc_at_smc_device); - dev->uart[0] = device_add_inst(&ns16550_device, 1); - dev->uart[1] = device_add_inst(&ns16550_device, 2); + dev->uart[0] = device_add_inst(&ns16450_device, 1); + dev->uart[1] = device_add_inst(&ns16450_device, 2); + + dev->chip_id = info->local & 0xff; + dev->has_ide = (info->local >> 8) & 0xff; io_sethandler(0x03f0, 0x0002, fdc37c661_read, NULL, NULL, fdc37c661_write, NULL, NULL, dev); fdc37c661_reset(dev); - + return dev; } + +/* The three appear to differ only in the chip ID, if I + understood their datasheets correctly. */ const device_t fdc37c661_device = { "SMC FDC37C661 Super I/O", 0, - 0, + 0x00, fdc37c661_init, fdc37c661_close, NULL, { NULL }, NULL, NULL, NULL }; +const device_t fdc37c661_ide_device = { + "SMC FDC37C661 Super I/O (With IDE)", + 0, + 0x100, + fdc37c661_init, fdc37c661_close, NULL, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/sio/sio_fdc37c669.c b/src/sio/sio_fdc37c669.c index b2d76814e..d223cf0df 100644 --- a/src/sio/sio_fdc37c669.c +++ b/src/sio/sio_fdc37c669.c @@ -33,7 +33,7 @@ typedef struct { - uint8_t tries, + uint8_t id, tries, regs[42]; int locked, rw_locked, cur_reg; @@ -42,6 +42,9 @@ typedef struct { } fdc37c669_t; +static int next_id = 0; + + static uint16_t make_port(fdc37c669_t *dev, uint8_t reg) { @@ -114,7 +117,7 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) switch(dev->cur_reg) { case 0: - if (valxor & 8) { + if (!dev->id && (valxor & 8)) { fdc_remove(dev->fdc); if ((dev->regs[0] & 8) && (dev->regs[0x20] & 0xc0)) fdc_set_base(dev->fdc, make_port(dev, 0x20)); @@ -122,9 +125,15 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) break; case 1: if (valxor & 4) { - lpt1_remove(); - if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) - lpt1_init(make_port(dev, 0x23)); + if (dev->id) { + lpt2_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt2_init(make_port(dev, 0x23)); + } else { + lpt1_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt1_init(make_port(dev, 0x23)); + } } if (valxor & 7) dev->rw_locked = (val & 8) ? 0 : 1; @@ -142,23 +151,23 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) } break; case 3: - if (valxor & 2) + if (!dev->id && (valxor & 2)) fdc_update_enh_mode(dev->fdc, (val & 2) ? 1 : 0); break; case 5: - if (valxor & 0x18) + if (!dev->id && (valxor & 0x18)) fdc_update_densel_force(dev->fdc, (val & 0x18) >> 3); - if (valxor & 0x20) + if (!dev->id && (valxor & 0x20)) fdc_set_swap(dev->fdc, (val & 0x20) >> 5); break; case 0xB: - if (valxor & 3) + if (!dev->id && (valxor & 3)) fdc_update_rwc(dev->fdc, 0, val & 3); - if (valxor & 0xC) + if (!dev->id && (valxor & 0xC)) fdc_update_rwc(dev->fdc, 1, (val & 0xC) >> 2); break; case 0x20: - if (valxor & 0xfc) { + if (!dev->id && (valxor & 0xfc)) { fdc_remove(dev->fdc); if ((dev->regs[0] & 8) && (dev->regs[0x20] & 0xc0)) fdc_set_base(dev->fdc, make_port(dev, 0x20)); @@ -166,9 +175,15 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) break; case 0x23: if (valxor) { - lpt1_remove(); - if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) - lpt1_init(make_port(dev, 0x23)); + if (dev->id) { + lpt2_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt2_init(make_port(dev, 0x23)); + } else { + lpt1_remove(); + if ((dev->regs[1] & 4) && (dev->regs[0x23] >= 0x40)) + lpt1_init(make_port(dev, 0x23)); + } } break; case 0x24: @@ -186,8 +201,12 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) } break; case 0x27: - if (valxor & 0xf) - lpt1_irq(val & 0xf); + if (valxor & 0xf) { + if (dev->id) + lpt2_irq(val & 0xf); + else + lpt1_irq(val & 0xf); + } break; case 0x28: if (valxor & 0xf) { @@ -226,17 +245,12 @@ fdc37c669_read(uint16_t port, void *priv) static void fdc37c669_reset(fdc37c669_t *dev) { - fdc_reset(dev->fdc); - serial_remove(dev->uart[0]); serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); serial_remove(dev->uart[1]); serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); - lpt1_remove(); - lpt1_init(0x378); - memset(dev->regs, 0, 42); dev->regs[0x00] = 0x28; dev->regs[0x01] = 0x9c; @@ -249,11 +263,27 @@ fdc37c669_reset(fdc37c669_t *dev) dev->regs[0x20] = (0x3f0 >> 2) & 0xfc; dev->regs[0x21] = (0x1f0 >> 2) & 0xfc; dev->regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; - dev->regs[0x23] = (0x378 >> 2); - dev->regs[0x24] = (0x3f8 >> 2) & 0xfe; - dev->regs[0x25] = (0x2f8 >> 2) & 0xfe; + if (dev->id == 1) { + dev->regs[0x23] = (0x278 >> 2); + + lpt2_remove(); + lpt2_init(0x278); + + dev->regs[0x24] = (SERIAL3_ADDR >> 2) & 0xfe; + dev->regs[0x25] = (SERIAL4_ADDR >> 2) & 0xfe; + } else { + fdc_reset(dev->fdc); + + lpt1_remove(); + lpt1_init(0x378); + + dev->regs[0x23] = (0x378 >> 2); + + dev->regs[0x24] = (SERIAL1_ADDR >> 2) & 0xfe; + dev->regs[0x25] = (SERIAL2_ADDR >> 2) & 0xfe; + } dev->regs[0x26] = (2 << 4) | 3; - dev->regs[0x27] = (6 << 4) | 7; + dev->regs[0x27] = (6 << 4) | (dev->id ? 5 : 7); dev->regs[0x28] = (4 << 4) | 3; dev->locked = 0; @@ -266,6 +296,8 @@ fdc37c669_close(void *priv) { fdc37c669_t *dev = (fdc37c669_t *) priv; + next_id = 0; + free(dev); } @@ -276,16 +308,21 @@ fdc37c669_init(const device_t *info) fdc37c669_t *dev = (fdc37c669_t *) malloc(sizeof(fdc37c669_t)); memset(dev, 0, sizeof(fdc37c669_t)); - dev->fdc = device_add(&fdc_at_smc_device); + dev->id = next_id; - dev->uart[0] = device_add_inst(&ns16550_device, 1); - dev->uart[1] = device_add_inst(&ns16550_device, 2); + if (next_id != 1) + dev->fdc = device_add(&fdc_at_smc_device); - io_sethandler(info->local ? 0x370 : 0x3f0, 0x0002, + dev->uart[0] = device_add_inst(&ns16550_device, (next_id << 1) + 1); + dev->uart[1] = device_add_inst(&ns16550_device, (next_id << 1) + 2); + + io_sethandler(info->local ? 0x370 : (next_id ? 0x370 : 0x3f0), 0x0002, fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, dev); fdc37c669_reset(dev); + next_id++; + return dev; } diff --git a/src/sio/sio_fdc37c66x.c b/src/sio/sio_fdc37c66x.c index 812bbf91b..ce8776944 100644 --- a/src/sio/sio_fdc37c66x.c +++ b/src/sio/sio_fdc37c66x.c @@ -256,7 +256,7 @@ fdc37c66x_reset(fdc37c66x_t *dev) dev->tries = 0; memset(dev->regs, 0, 16); - dev->regs[0x0] = 0x2a; + dev->regs[0x0] = 0x3a; dev->regs[0x1] = 0x9f; dev->regs[0x2] = 0xdc; dev->regs[0x3] = 0x78; diff --git a/src/sio/sio_w83977f.c b/src/sio/sio_w83977f.c index dc3f1c012..46a75ac9e 100644 --- a/src/sio/sio_w83977f.c +++ b/src/sio/sio_w83977f.c @@ -268,11 +268,11 @@ w83977f_write(uint16_t port, uint8_t val, void *priv) if (dev->id == 1) break; - if (valxor & 0x20) + if (!dev->id && (valxor & 0x20)) fdc_update_drv2en(dev->fdc, (val & 0x20) ? 0 : 1); - if (valxor & 0x10) + if (!dev->id && (valxor & 0x10)) fdc_set_swap(dev->fdc, (val & 0x10) ? 1 : 0); - if (valxor & 0x01) + if (!dev->id && (valxor & 0x01)) fdc_update_enh_mode(dev->fdc, (val & 0x01) ? 1 : 0); break; case 0x01: @@ -291,13 +291,13 @@ w83977f_write(uint16_t port, uint8_t val, void *priv) if (dev->id == 1) break; - if (valxor & 0xc0) + if (!dev->id && (valxor & 0xc0)) fdc_update_boot_drive(dev->fdc, (val & 0xc0) >> 6); - if (valxor & 0x0c) + if (!dev->id && (valxor & 0x0c)) fdc_update_densel_force(dev->fdc, (val & 0x0c) >> 2); - if (valxor & 0x02) + if (!dev->id && (valxor & 0x02)) fdc_set_diswr(dev->fdc, (val & 0x02) ? 1 : 0); - if (valxor & 0x01) + if (!dev->id && (valxor & 0x01)) fdc_set_swwp(dev->fdc, (val & 0x01) ? 1 : 0); break; } @@ -308,13 +308,13 @@ w83977f_write(uint16_t port, uint8_t val, void *priv) if (dev->id == 1) break; - if (valxor & 0xc0) + if (!dev->id && (valxor & 0xc0)) fdc_update_rwc(dev->fdc, 3, (val & 0xc0) >> 6); - if (valxor & 0x30) + if (!dev->id && (valxor & 0x30)) fdc_update_rwc(dev->fdc, 2, (val & 0x30) >> 4); - if (valxor & 0x0c) + if (!dev->id && (valxor & 0x0c)) fdc_update_rwc(dev->fdc, 1, (val & 0x0c) >> 2); - if (valxor & 0x03) + if (!dev->id && (valxor & 0x03)) fdc_update_rwc(dev->fdc, 0, val & 0x03); break; } @@ -325,7 +325,7 @@ w83977f_write(uint16_t port, uint8_t val, void *priv) if (dev->id == 1) break; - if (valxor & 0x18) + if (!dev->id && (valxor & 0x18)) fdc_update_drvrate(dev->fdc, dev->cur_reg & 0x03, (val & 0x18) >> 3); break; } @@ -347,7 +347,7 @@ w83977f_read(uint16_t port, void *priv) ret = dev->cur_reg; else { if (!dev->rw_locked) { - if ((dev->cur_reg == 0xf2) && (ld == 0x00)) + if (!dev->id && ((dev->cur_reg == 0xf2) && (ld == 0x00))) ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6)); else if (dev->cur_reg >= 0x30) ret = dev->dev_regs[ld][dev->cur_reg - 0x30]; @@ -506,7 +506,7 @@ w83977f_reset(w83977f_t *dev) dev->dev_regs[10][0xc0] = 0x8f; } - if (next_id == 1) { + if (dev->id == 1) { serial_setup(dev->uart[0], SERIAL3_ADDR, SERIAL3_IRQ); serial_setup(dev->uart[1], SERIAL4_ADDR, SERIAL4_IRQ); } else {