From 3d65f69949d2063b49d6469d0f34797ca3dda1a2 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 23 Oct 2023 15:50:19 -0300 Subject: [PATCH] Rewrite IT8661F and add IT8671F --- src/include/86box/sio.h | 1 + src/sio/CMakeLists.txt | 2 +- src/sio/sio_it8661f.c | 353 ---------------- src/sio/sio_it86x1f.c | 862 ++++++++++++++++++++++++++++++++++++++++ src/win/Makefile.mingw | 2 +- 5 files changed, 865 insertions(+), 355 deletions(-) delete mode 100644 src/sio/sio_it8661f.c create mode 100644 src/sio/sio_it86x1f.c diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index 2736a4eb5..b51f466e4 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -42,6 +42,7 @@ extern const device_t fdc37c935_device; extern const device_t fdc37m60x_device; extern const device_t fdc37m60x_370_device; extern const device_t it8661f_device; +extern const device_t it8671f_device; extern const device_t i82091aa_device; extern const device_t i82091aa_398_device; extern const device_t i82091aa_ide_pri_device; diff --git a/src/sio/CMakeLists.txt b/src/sio/CMakeLists.txt index 15411d3e6..3140a7181 100644 --- a/src/sio/CMakeLists.txt +++ b/src/sio/CMakeLists.txt @@ -15,7 +15,7 @@ add_library(sio OBJECT sio_acc3221.c sio_ali5123.c sio_f82c710.c sio_82091aa.c sio_fdc37c6xx.c sio_fdc37c67x.c sio_fdc37c669.c sio_fdc37c93x.c sio_fdc37m60x.c - sio_it8661f.c + sio_it86x1f.c sio_pc87306.c sio_pc87307.c sio_pc87309.c sio_pc87310.c sio_pc87311.c sio_pc87332.c sio_prime3b.c sio_prime3c.c sio_w83787f.c sio_w83877f.c sio_w83977f.c sio_um8669f.c diff --git a/src/sio/sio_it8661f.c b/src/sio/sio_it8661f.c deleted file mode 100644 index 5367ffedf..000000000 --- a/src/sio/sio_it8661f.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * 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. - * - * Implementation of the ITE IT8661F chipset. - * - * Note: This Super I/O is partially incomplete and intended only for having the intended machine to function - * - * Authors: Tiseno100 - * - * Copyright 2021 Tiseno100 - * - */ -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/io.h> -#include <86box/timer.h> -#include <86box/device.h> -#include <86box/lpt.h> -#include <86box/serial.h> -#include <86box/fdd.h> -#include <86box/fdc.h> -#include <86box/fdd_common.h> -#include <86box/sio.h> -#include <86box/plat_unused.h> - -#define LDN dev->regs[7] - -typedef struct it8661f_t { - fdc_t *fdc_controller; - serial_t *uart[2]; - - uint8_t index; - uint8_t regs[256]; - uint8_t device_regs[6][256]; - int unlocked; - int enumerator; -} it8661f_t; - -static uint8_t mb_pnp_key[32] = { 0x6a, 0xb5, 0xda, 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b, 0x0d, 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, 0xd1, 0xe8, 0x74, 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 }; - -static void it8661f_reset(void *priv); - -#ifdef ENABLE_IT8661_LOG -int it8661_do_log = ENABLE_IT8661_LOG; - -void -it8661_log(const char *fmt, ...) -{ - va_list ap; - - if (it8661_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -# define it8661_log(fmt, ...) -#endif - -static void -it8661_fdc(uint16_t addr, uint8_t val, it8661f_t *dev) -{ - fdc_remove(dev->fdc_controller); - - if (((addr == 0x30) && (val & 1)) || (dev->device_regs[0][0x30] & 1)) { - switch (addr) { - case 0x30: - dev->device_regs[0][addr] = val & 1; - break; - - case 0x31: - dev->device_regs[0][addr] = val & 3; - if (val & 1) - dev->device_regs[0][addr] |= 0x55; - break; - - case 0x60: - case 0x61: - dev->device_regs[0][addr] = val & ((addr == 0x61) ? 0xff : 0xf8); - break; - - case 0x70: - dev->device_regs[0][addr] = val & 0x0f; - break; - - case 0x74: - dev->device_regs[0][addr] = val & 7; - break; - - case 0xf0: - dev->device_regs[0][addr] = val & 0x0f; - break; - - default: - break; - } - - fdc_set_base(dev->fdc_controller, (dev->device_regs[0][0x60] << 8) | (dev->device_regs[0][0x61])); - fdc_set_irq(dev->fdc_controller, dev->device_regs[0][0x70] & 0x0f); - fdc_set_dma_ch(dev->fdc_controller, dev->device_regs[0][0x74] & 7); - - if (dev->device_regs[0][0xf0] & 1) - fdc_writeprotect(dev->fdc_controller); - - it8661_log("ITE 8661-FDC: BASE %04x IRQ %02x\n", (dev->device_regs[0][0x60] << 8) | (dev->device_regs[0][0x61]), - dev->device_regs[0][0x70] & 0x0f); - } -} - -static void -it8661_serial(int uart, uint16_t addr, uint8_t val, it8661f_t *dev) -{ - serial_remove(dev->uart[uart]); - - if (((addr == 0x30) && (val & 1)) || (dev->device_regs[1 + uart][0x30] & 1)) { - switch (addr) { - case 0x30: - dev->device_regs[1 + uart][addr] = val & 1; - break; - - case 0x60: - case 0x61: - dev->device_regs[1 + uart][addr] = val & ((addr == 0x61) ? 0xff : 0xf8); - break; - - case 0x70: - dev->device_regs[1 + uart][addr] = val & 0x0f; - break; - - case 0x74: - dev->device_regs[1 + uart][addr] = val & 7; - break; - - case 0xf0: - dev->device_regs[1 + uart][addr] = val & 3; - break; - - default: - break; - } - - serial_setup(dev->uart[uart], (dev->device_regs[1 + uart][0x60] << 8) | (dev->device_regs[1 + uart][0x61]), dev->device_regs[1 + uart][0x70] & 0x0f); - - it8661_log("ITE 8661-UART%01x: BASE %04x IRQ %02x\n", 1 + (LDN % 1), - (dev->device_regs[1 + uart][0x60] << 8) | (dev->device_regs[1 + uart][0x61]), - dev->device_regs[1 + uart][0x70] & 0x0f); - } -} - -void -it8661_lpt(uint16_t addr, uint8_t val, it8661f_t *dev) -{ - lpt1_remove(); - - if (((addr == 0x30) && (val & 1)) || (dev->device_regs[3][0x30] & 1)) { - switch (addr) { - case 0x30: - dev->device_regs[3][addr] = val & 1; - break; - - case 0x60: - case 0x61: - dev->device_regs[3][addr] = val & ((addr == 0x61) ? 0xff : 0xf8); - break; - - case 0x70: - dev->device_regs[3][addr] = val & 0x0f; - break; - - case 0x74: - dev->device_regs[3][addr] = val & 7; - break; - - case 0xf0: - dev->device_regs[3][addr] = val & 3; - break; - - default: - break; - } - - lpt1_init((dev->device_regs[3][0x60] << 8) | (dev->device_regs[3][0x61])); - lpt1_irq(dev->device_regs[3][0x70] & 0x0f); - - it8661_log("ITE 8661-LPT: BASE %04x IRQ %02x\n", (dev->device_regs[3][0x60] << 8) | (dev->device_regs[3][0x61]), - dev->device_regs[3][0x70] & 0x0f); - } -} - -void -it8661_ldn(uint16_t addr, uint8_t val, it8661f_t *dev) -{ - switch (LDN) { - case 0: - it8661_fdc(addr, val, dev); - break; - case 1: - case 2: - it8661_serial((LDN & 2) - 1, addr, val, dev); - break; - case 3: - it8661_lpt(addr, val, dev); - break; - - default: - break; - } -} - -static void -it8661f_write(uint16_t addr, uint8_t val, void *priv) -{ - it8661f_t *dev = (it8661f_t *) priv; - - switch (addr) { - case FDC_SECONDARY_ADDR: - if (!dev->unlocked) { - (val == mb_pnp_key[dev->enumerator]) ? dev->enumerator++ : (dev->enumerator = 0); - if (dev->enumerator == 31) { - dev->unlocked = 1; - it8661_log("ITE8661F: Unlocked!\n"); - } - } else - dev->index = val; - break; - - case 0x371: - if (dev->unlocked) { - switch (dev->index) { - case 0x02: - dev->regs[dev->index] = val; - if (val & 1) - it8661f_reset(dev); - if (val & 2) - dev->unlocked = 0; - break; - case 0x07: - dev->regs[dev->index] = val; - break; - case 0x22: - dev->regs[dev->index] = val & 0x30; - break; - case 0x23: - dev->regs[dev->index] = val & 0x1f; - break; - default: - it8661_ldn(dev->index, val, dev); - break; - } - } - break; - - default: - break; - } - - return; -} - -static uint8_t -it8661f_read(uint16_t addr, void *priv) -{ - const it8661f_t *dev = (it8661f_t *) priv; - - it8661_log("IT8661F:\n", addr, dev->regs[dev->index]); - return (addr == 0xa79) ? dev->regs[dev->index] : 0xff; -} - -static void -it8661f_reset(void *priv) -{ - it8661f_t *dev = (it8661f_t *) priv; - dev->regs[0x20] = 0x86; - dev->regs[0x21] = 0x61; - - dev->device_regs[0][0x60] = 3; - dev->device_regs[0][0x61] = 0xf0; - dev->device_regs[0][0x70] = 6; - dev->device_regs[0][0x71] = 2; - dev->device_regs[0][0x74] = 2; - - dev->device_regs[1][0x60] = 3; - dev->device_regs[1][0x61] = 0xf8; - dev->device_regs[1][0x70] = 4; - dev->device_regs[1][0x71] = 2; - - dev->device_regs[2][0x60] = 2; - dev->device_regs[2][0x61] = 0xf8; - dev->device_regs[2][0x70] = 3; - dev->device_regs[2][0x71] = 2; - - dev->device_regs[3][0x60] = 3; - dev->device_regs[3][0x61] = 0x78; - dev->device_regs[3][0x70] = 7; - dev->device_regs[3][0x71] = 2; - dev->device_regs[3][0x74] = 3; - dev->device_regs[3][0xf0] = 3; -} - -static void -it8661f_close(void *priv) -{ - it8661f_t *dev = (it8661f_t *) priv; - - free(dev); -} - -static void * -it8661f_init(UNUSED(const device_t *info)) -{ - it8661f_t *dev = (it8661f_t *) malloc(sizeof(it8661f_t)); - memset(dev, 0, sizeof(it8661f_t)); - - dev->fdc_controller = device_add(&fdc_at_smc_device); - fdc_reset(dev->fdc_controller); - - dev->uart[0] = device_add_inst(&ns16550_device, 1); - dev->uart[1] = device_add_inst(&ns16550_device, 2); - - io_sethandler(FDC_SECONDARY_ADDR, 0x0002, it8661f_read, NULL, NULL, it8661f_write, NULL, NULL, dev); - - dev->enumerator = 0; - dev->unlocked = 0; - - it8661f_reset(dev); - return dev; -} - -const device_t it8661f_device = { - .name = "ITE IT8661F", - .internal_name = "it8661f", - .flags = 0, - .local = 0, - .init = it8661f_init, - .close = it8661f_close, - .reset = NULL, - { .available = NULL }, - .speed_changed = NULL, - .force_redraw = NULL, - .config = NULL -}; diff --git a/src/sio/sio_it86x1f.c b/src/sio/sio_it86x1f.c new file mode 100644 index 000000000..91dcc756b --- /dev/null +++ b/src/sio/sio_it86x1f.c @@ -0,0 +1,862 @@ +/* + * 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. + * + * Emulation of the ITE IT86x1F Super I/O chips. + * + * + * + * Authors: RichardG, + * + * Copyright 2023 RichardG. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/pci.h> +#include <86box/lpt.h> +#include <86box/serial.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/gameport.h> +#include <86box/sio.h> +#include <86box/isapnp.h> +#include <86box/plat_fallthrough.h> +#include <86box/plat_unused.h> + +enum { + ITE_IT8661F = 0x8661, + ITE_IT8671F = 0x8681 +}; + +#define CHIP_ID *((uint16_t *) &dev->global_regs[0]) + +static void it8671f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); +static void it8661f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); + +static const struct { + uint16_t chip_id; + uint16_t unlock_id; + uint8_t gpio_ldn; + /* Fake ROMs to delegate all the logical device register handling over to the ISAPnP subsystem. + The actual ROMs/IDs used by real chips when those are set to ISAPnP mode remain to be seen. */ + uint8_t *pnp_rom; + + const isapnp_device_config_t *pnp_defaults; + + void (*pnp_config_changed)(uint8_t ld, isapnp_device_config_t *config, void *priv); +} it86x1f_models[] = { + { + .chip_id = ITE_IT8661F, + .unlock_id = 0x8661, + .gpio_ldn = 0x05, + .pnp_rom = (uint8_t[]) { + 0x26, 0x85, 0x86, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, /* ITE8661, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ + + 0x15, 0x41, 0xd0, 0x07, 0x00, 0x01, /* logical device PNP0700, can participate in boot */ + 0x23, 0xf8, 0x0f, 0x02, /* IRQ 3/4/5/6/7/8/9/10/11, low true edge sensitive */ + 0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x41, 0xd0, 0x05, 0x01, 0x01, /* logical device PNP0501, can participate in boot */ + 0x23, 0xf8, 0x0f, 0x02, /* IRQ 3/4/5/6/7/8/9/10/11, low true edge sensitive */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x41, 0xd0, 0x05, 0x01, 0x01, /* logical device PNP0501, can participate in boot */ + 0x23, 0xf8, 0x0f, 0x02, /* IRQ 3/4/5/6/7/8/9/10/11, low true edge sensitive */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x41, 0xd0, 0x04, 0x00, 0x01, /* logical device PNP0400, can participate in boot */ + 0x23, 0xf8, 0x0f, 0x02, /* IRQ 3/4/5/6/7/8/9/10/11, low true edge sensitive */ + 0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x47, 0x01, 0x00, 0x01, 0xfc, 0x0f, 0x04, 0x04, /* I/O 0x100-0xFFC, decodes 16-bit, 4-byte alignment, 4 addresses */ + + 0x15, 0x41, 0xd0, 0x05, 0x10, 0x01, /* logical device PNP0510, can participate in boot */ + 0x23, 0xf8, 0x0f, 0x02, /* IRQ 3/4/5/6/7/8/9/10/11, low true edge sensitive */ + 0x23, 0xf8, 0x0f, 0x02, /* IRQ 3/4/5/6/7/8/9/10/11, low true edge sensitive */ + 0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ + }, + .pnp_defaults = (const isapnp_device_config_t[]) { + { + .activate = 0, + .io = { { .base = FDC_PRIMARY_ADDR }, }, + .irq = { { .irq = FDC_PRIMARY_IRQ }, }, + .dma = { { .dma = FDC_PRIMARY_DMA }, } + }, { + .activate = 0, + .io = { { .base = COM1_ADDR }, }, + .irq = { { .irq = COM1_IRQ }, } + }, { + .activate = 0, + .io = { { .base = COM2_ADDR }, }, + .irq = { { .irq = COM2_IRQ }, } + }, { + .activate = 0, + .io = { { .base = LPT1_ADDR }, { .base = 0x778 }, }, + .irq = { { .irq = LPT1_IRQ }, }, + .dma = { { .dma = 3 }, } + }, { + .activate = 0, + .io = { { .base = COM4_ADDR }, { .base = 0x300 }, }, + .irq = { { .irq = 10 }, { .irq = 11 }, }, + .dma = { { .dma = 1 }, { .dma = 0 }, } + }, { + .activate = -1 + } + }, + .pnp_config_changed = it8661f_pnp_config_changed + }, { + .chip_id = ITE_IT8671F, + .unlock_id = 0x8680, + .gpio_ldn = 0x07, + .pnp_rom = (uint8_t[]) { + 0x26, 0x85, 0x86, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, /* ITE8671, dummy checksum (filled in by isapnp_add_card) */ + 0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */ + + 0x15, 0x41, 0xd0, 0x07, 0x00, 0x01, /* logical device PNP0700, can participate in boot */ + 0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */ + 0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x41, 0xd0, 0x05, 0x01, 0x01, /* logical device PNP0501, can participate in boot */ + 0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x41, 0xd0, 0x05, 0x10, 0x01, /* logical device PNP0510, can participate in boot */ + 0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */ + 0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */ + 0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + + 0x15, 0x41, 0xd0, 0x04, 0x00, 0x01, /* logical device PNP0400, can participate in boot */ + 0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */ + 0x2a, 0x0f, 0x0c, /* DMA 0/1/2/3, compatibility, no count by word, count by byte, is bus master, 8-bit only */ + 0x47, 0x01, 0x00, 0x01, 0xf8, 0x0f, 0x08, 0x08, /* I/O 0x100-0xFF8, decodes 16-bit, 8-byte alignment, 8 addresses */ + 0x47, 0x01, 0x00, 0x01, 0xfc, 0x0f, 0x04, 0x04, /* I/O 0x100-0xFFC, decodes 16-bit, 4-byte alignment, 4 addresses */ + + 0x15, 0x41, 0xd0, 0xff, 0xff, 0x00, /* logical device PNPFFFF (dummy to create APC gap in LDNs) */ + + 0x15, 0x41, 0xd0, 0x03, 0x03, 0x01, /* logical device PNP0303, can participate in boot */ + 0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */ + 0x47, 0x01, 0x00, 0x00, 0xff, 0x0f, 0x01, 0x01, /* I/O 0x0-0xFFF, decodes 16-bit, 1-byte alignment, 1 address */ + 0x47, 0x01, 0x00, 0x00, 0xff, 0x0f, 0x01, 0x01, /* I/O 0x0-0xFFF, decodes 16-bit, 1-byte alignment, 1 address */ + + 0x15, 0x41, 0xd0, 0x0f, 0x13, 0x01, /* logical device PNP0F13, can participate in boot */ + 0x23, 0xfa, 0x1f, 0x02, /* IRQ 1/3/4/5/6/7/8/9/10/11/12, low true edge sensitive */ + + 0x79, 0x00 /* end tag, dummy checksum (filled in by isapnp_add_card) */ + }, + .pnp_defaults = (const isapnp_device_config_t[]) { + { + .activate = 0, + .io = { { .base = FDC_PRIMARY_ADDR }, }, + .irq = { { .irq = FDC_PRIMARY_IRQ }, }, + .dma = { { .dma = FDC_PRIMARY_DMA }, } + }, { + .activate = 0, + .io = { { .base = COM1_ADDR }, }, + .irq = { { .irq = COM1_IRQ }, } + }, { + .activate = 0, + .io = { { .base = COM2_ADDR }, { .base = 0x300 }, }, + .irq = { { .irq = COM2_IRQ }, { .irq = 10 }, }, + .dma = { { .dma = 0 }, { .dma = 1 }, } + }, { + .activate = 0, + .io = { { .base = LPT1_ADDR }, { .base = 0x778 }, }, + .irq = { { .irq = LPT1_IRQ }, }, + .dma = { { .dma = 3 }, } + }, { + .activate = 0 + }, { + .activate = 1, + .io = { { .base = 0x60 }, { .base = 0x64 }, }, + .irq = { { .irq = 1 }, } + }, { + .activate = 0, + .irq = { { .irq = 12 }, } + }, { + .activate = -1 + } + }, + .pnp_config_changed = it8671f_pnp_config_changed + } +}; + +#ifdef ENABLE_IT86X1F_LOG +int it86x1f_do_log = ENABLE_IT86X1F_LOG; + +static void +it86x1f_log(const char *fmt, ...) +{ + va_list ap; + + if (it86x1f_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define it86x1f_log(fmt, ...) +#endif + +typedef struct it86x1f_t { + uint8_t instance; + uint8_t locked; + uint8_t cur_ldn; + uint8_t cur_reg; + void *pnp_card; + uint8_t global_regs[16]; /* [0x20:0x2f] */ + uint8_t ldn_regs[8][16]; /* [0xf0:0xff] */ + uint8_t gpio_regs[36]; /* [0x60:0x7f] then [0xe0:0xe3] */ + uint8_t gpio_ldn; + + uint16_t unlock_id; + uint16_t addr_port; + uint16_t data_port; + uint8_t unlock_val; + uint8_t unlock_pos : 2; + uint8_t key_pos : 5; + + fdc_t *fdc; + serial_t *uart[2]; + void *gameport; +} it86x1f_t; + +static void it86x1f_remap(it86x1f_t *dev, uint16_t addr_port, uint16_t data_port); + +static void +it8661f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + if (ld > 5) { + it86x1f_log("IT86x1F: Unknown logical device %d\n", ld); + return; + } + + it86x1f_t *dev = (it86x1f_t *) priv; + + switch (ld) { + case 0: + fdc_remove(dev->fdc); + + if (config->activate) { + it86x1f_log("IT86x1F: FDC enabled at port %04X IRQ %d DMA %d\n", config->io[0].base, config->irq[0].irq, (config->dma[0].dma == ISAPNP_DMA_DISABLED) ? -1 : config->dma[0].dma); + + if (config->io[0].base != ISAPNP_IO_DISABLED) + fdc_set_base(dev->fdc, config->io[0].base); + + fdc_set_irq(dev->fdc, config->irq[0].irq); + fdc_set_dma_ch(dev->fdc, (config->dma[0].dma == ISAPNP_DMA_DISABLED) ? -1 : config->dma[0].dma); + } else { + it86x1f_log("IT86x1F: FDC disabled\n"); + } + + break; + + case 1: + case 2: + serial_remove(dev->uart[ld - 1]); + + if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { + it86x1f_log("IT86x1F: UART %d enabled at port %04X IRQ %d\n", ld - 1, config->io[0].base, config->irq[0].irq); + serial_setup(dev->uart[ld - 1], config->io[0].base, config->irq[0].irq); + } else { + it86x1f_log("IT86x1F: UART %d disabled\n", ld - 1); + } + + break; + + case 3: + lpt1_remove(); + + if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { + it86x1f_log("IT86x1F: LPT enabled at port %04X IRQ %d\n", config->io[0].base, config->irq[0].irq); + lpt1_init(config->io[0].base); + } else { + it86x1f_log("IT86x1F: LPT disabled\n"); + } + + break; + + case 4: + if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) { + it86x1f_log("IT86x1F: IR enabled at ports %04X %04X IRQs %d %d DMAs %d %d\n", config->io[0].base, config->io[1].base, config->irq[0].irq, config->irq[1].irq, (config->dma[0].dma == ISAPNP_DMA_DISABLED) ? -1 : config->dma[0].dma, (config->dma[1].dma == ISAPNP_DMA_DISABLED) ? -1 : config->dma[1].dma); + } else { + it86x1f_log("IT86x1F: IR disabled\n"); + } + break; + + default: + break; + } +} + +static void +it8671f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + it86x1f_t *dev = (it86x1f_t *) priv; + + switch (ld) { + case 2: + it8661f_pnp_config_changed(4, config, dev); /* just for logging, should change if IR UART is implemented */ + fallthrough; + + case 0 ... 1: + case 3: + it8661f_pnp_config_changed(ld, config, dev); + break; + + case 5: + if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED) && (config->io[1].base != ISAPNP_IO_DISABLED)) { + it86x1f_log("IT86x1F: KBC enabled at ports %04X %04X IRQ %d\n", config->io[0].base, config->io[1].base, config->irq[0].irq); + } else { + it86x1f_log("IT86x1F: KBC disabled\n"); + } + break; + + case 6: + if (config->activate) { + it86x1f_log("IT86x1F: KBC mouse enabled at IRQ %d\n", config->irq[0].irq); + } else { + it86x1f_log("IT86x1F: KBC mouse disabled\n"); + } + break; + + default: + break; + } +} + +static uint8_t +it86x1f_pnp_read_vendor_reg(uint8_t ld, uint8_t reg, void *priv) +{ + it86x1f_t *dev = (it86x1f_t *) priv; + uint8_t ret = 0xff; + + switch (reg) { + case 0x20 ... 0x2f: + ret = dev->global_regs[reg & 0x0f]; + break; + + case 0x60 ... 0x7f: + if (ld != dev->gpio_ldn) + break; + + ret = dev->gpio_regs[reg & 0x1f]; + break; + + case 0xe0 ... 0xe3: + if (ld != dev->gpio_ldn) + break; + + ret = dev->gpio_regs[0x20 | (reg & 0x03)]; + break; + + case 0xf0 ... 0xff: + if (ld > dev->gpio_ldn) + break; + + ret = dev->ldn_regs[ld][reg & 0x0f]; + break; + + default: + break; + } + + it86x1f_log("IT86x1F: read_vendor_reg(%X, %02X) = %02X\n", ld, reg, ret); + + return ret; +} + +static void +it86x1f_pnp_write_vendor_reg(uint8_t ld, uint8_t reg, uint8_t val, void *priv) +{ + it86x1f_t *dev = (it86x1f_t *) priv; + + it86x1f_log("IT86x1F: write_vendor_reg(%X, %02X, %02X)\n", ld, reg, val); + + switch (reg) { + case 0x22: + if (CHIP_ID == ITE_IT8661F) { + dev->global_regs[reg & 0x0f] = (val & 0x30) | (dev->global_regs[reg & 0x0f] & ~0x30); + uint8_t mcc = (val & 0x30) >> 4; + if (mcc != dev->instance) { + it86x1f_log("IT86x1F: Instance %d unmapping as ID %d was written\n", dev->instance, mcc); + it86x1f_remap(dev, 0, 0); + } + } + break; + + case 0x23: + val &= (1 << dev->gpio_ldn) - 1; + dev->global_regs[reg & 0x0f] = val; + if (val) + pclog("IT86x1F: Warning: ISAPnP mode enabled.\n"); + break; + + case 0x24: + dev->global_regs[reg & 0x0f] = val & ((CHIP_ID == ITE_IT8661F) ? 0x03 : 0x5f); + break; + + case 0x25: + val &= (CHIP_ID == ITE_IT8661F) ? 0x1f : 0xf0; + fallthrough; + + case 0x26: + if (ld == dev->gpio_ldn) + dev->global_regs[reg & 0x0f] = val; + break; + + case 0x2e ... 0x2f: + if ((CHIP_ID == ITE_IT8671F) && (ld == 0xf4)) + dev->global_regs[reg & 0x0f] = val; + break; + + case 0x60 ... 0x7f: + if (ld != dev->gpio_ldn) + break; + + dev->gpio_regs[reg & 0x1f] = val; + break; + + case 0xe0 ... 0xe3: + if (ld != dev->gpio_ldn) + break; + + dev->gpio_regs[0x20 | (reg & 0x0f)] = val; + break; + + case 0xf0 ... 0xff: + /* Translate GPIO LDN to 7 for the switch block. */ + uint8_t effective_ldn; + if (ld == dev->gpio_ldn) + effective_ldn = 7; + else if (ld == 7) + effective_ldn = 8; /* dummy */ + else + effective_ldn = ld; + + switch ((effective_ldn << 8) | reg) { + case 0x0f0: + dev->ldn_regs[ld][reg & 0x0f] = val & 0x0f; + fdc_set_swwp(dev->fdc, !!(val & 0x01)); + fdc_set_swap(dev->fdc, !!(val & 0x04)); + break; + + case 0x1f0: + dev->ldn_regs[ld][reg & 0x0f] = val & 0x03; + break; + + case 0x2f0: + dev->ldn_regs[ld][reg & 0x0f] = val & ((CHIP_ID == ITE_IT8661F) ? 0x03 : 0xf3); + break; + + case 0x2f1: + if (CHIP_ID == ITE_IT8671F) + dev->ldn_regs[ld][reg & 0x0f] = val & 0xb7; + break; + + case 0x3f0: + dev->ldn_regs[ld][reg & 0x0f] = val & 0x07; + break; + + case 0x4f0: + if (CHIP_ID == ITE_IT8661F) + val &= 0x3f; + dev->ldn_regs[ld][reg & 0x0f] = val; + break; + + case 0x4f1: + if (CHIP_ID == ITE_IT8671F) + dev->ldn_regs[ld][reg & 0x0f] = val & 0x7f; + break; + + case 0x4f2: + case 0x4f6: + if (CHIP_ID == ITE_IT8671F) + dev->ldn_regs[ld][reg & 0x0f] = val; + break; + + case 0x4f7: + if (CHIP_ID == ITE_IT8671F) + dev->ldn_regs[ld][reg & 0x0f] = val & 0x7f; + break; + + case 0x4f8: + if (CHIP_ID == ITE_IT8671F) + dev->ldn_regs[ld][reg & 0x0f] = val & 0x07; + break; + + case 0x5f0: + dev->ldn_regs[ld][reg & 0x0f] = val & 0x1f; + break; + + case 0x6f0: + if (CHIP_ID == ITE_IT8671F) + dev->ldn_regs[ld][reg & 0x0f] = val & 0x03; + break; + + case 0x760: + case 0x762: + case 0x764: + case 0x766: + dev->gpio_regs[reg & 0x1f] = val & 0x0f; + break; + + case 0x772: + if (CHIP_ID != ITE_IT8671F) + break; + fallthrough; + + case 0x761: + case 0x763: + case 0x765: + case 0x767: + case 0x770: + dev->gpio_regs[reg & 0x1f] = val; + + case 0x771: + if (CHIP_ID == ITE_IT8671F) + dev->gpio_regs[reg & 0x1f] = val & 0xde; + break; + + case 0x7e0: + if (CHIP_ID == ITE_IT8671F) + dev->gpio_regs[0x20 | (reg & 0x03)] = val & 0xef; + break; + + case 0x7e1: + if (CHIP_ID == ITE_IT8671F) + dev->gpio_regs[0x20 | (reg & 0x03)] = val & 0x7f; + break; + + case 0x7e3: + if ((CHIP_ID == ITE_IT8671F) && (val & 0x80)) + *((uint16_t *) &dev->gpio_regs[0x22]) = 0x0000; + break; + + case 0x7fb: + if (CHIP_ID == ITE_IT8671F) + val &= 0x7f; + fallthrough; + + case 0x7f0 ... 0x7f5: + dev->ldn_regs[ld][reg & 0x0f] = val; + break; + + case 0x7f6: + dev->ldn_regs[ld][reg & 0x0f] = val & ((CHIP_ID == ITE_IT8661F) ? 0x3f : 0xcf); + break; + + case 0x7f7: + dev->ldn_regs[ld][reg & 0x0f] = val & ((CHIP_ID == ITE_IT8661F) ? 0x9f : 0xdf); + break; + + case 0x7f8 ... 0x7fa: + dev->ldn_regs[ld][reg & 0x0f] = val & ((CHIP_ID == ITE_IT8661F) ? 0x1f : 0x0f); + break; + + case 0x7fc: + if (CHIP_ID == ITE_IT8661F) + dev->ldn_regs[ld][reg & 0x0f] = val; + break; + + case 0x7ff: + if (CHIP_ID == ITE_IT8671F) + dev->ldn_regs[ld][reg & 0x0f] = val & 0x2f; + break; + + default: + break; + } + break; + + default: + break; + } +} + +static void +it86x1f_write_addr(uint16_t port, uint8_t val, void *priv) +{ + it86x1f_t *dev = (it86x1f_t *) priv; + + it86x1f_log("IT86x1F: write_addr(%04X, %02X)\n", port, val); + + if (dev->locked) { + if (val == isapnp_init_key[dev->key_pos]) { + if (++dev->key_pos == 0) { + it86x1f_log("IT86x1F: Unlocked\n"); + dev->locked = 0; + } + } else { + dev->key_pos = 0; + } + } else { + dev->cur_reg = val; + } +} + +static void +it86x1f_write_data(uint16_t port, uint8_t val, void *priv) +{ + it86x1f_t *dev = (it86x1f_t *) priv; + + it86x1f_log("IT86x1F: write_data(%04X, %02X)\n", port, val); + + if (dev->locked) + return; + + switch (dev->cur_reg) { + case 0x00 ... 0x01: + case 0x03 ... 0x06: + case 0x31: + case 0x71: + case 0x73: + break; /* ISAPnP-only */ + + case 0x07: + dev->cur_ldn = val; + break; + + case 0x02: + if (val & 0x02) { + it86x1f_log("IT86x1F: Locked => "); + dev->locked = 1; + it86x1f_remap(dev, 0, 0); + } + fallthrough; + + default: + isapnp_write_reg(dev->pnp_card, dev->cur_ldn, dev->cur_reg, val); + break; + } +} + +static uint8_t +it86x1f_read_addr(uint16_t port, void *priv) +{ + it86x1f_t *dev = (it86x1f_t *) priv; + uint8_t ret = dev->locked ? 0xff : dev->cur_reg; + + it86x1f_log("IT86x1F: read_addr(%04X) = %02X\n", port, ret); + + return ret; +} + +static uint8_t +it86x1f_read_data(uint16_t port, void *priv) +{ + it86x1f_t *dev = (it86x1f_t *) priv; + uint8_t ret = 0xff; + + switch (dev->cur_reg) { + case 0x00 ... 0x01: + case 0x03 ... 0x06: + case 0x31: + case 0x71: + case 0x73: + break; /* ISAPnP-only */ + + case 0x07: + ret = dev->cur_ldn; + break; + + default: + ret = isapnp_read_reg(dev->pnp_card, dev->cur_ldn, dev->cur_reg); + break; + } + + it86x1f_log("IT86x1F: read_data(%04X) = %02X\n", port, ret); + + return ret; +} + +static void +it86x1f_remap(it86x1f_t *dev, uint16_t addr_port, uint16_t data_port) +{ + if (dev->addr_port) + io_removehandler(dev->addr_port, 1, it86x1f_read_addr, NULL, NULL, it86x1f_write_addr, NULL, NULL, dev); + if (dev->data_port) + io_removehandler(dev->data_port, 1, it86x1f_read_data, NULL, NULL, it86x1f_write_data, NULL, NULL, dev); + + it86x1f_log("IT86x1F: remap(%04X, %04X)\n", addr_port, data_port); + dev->addr_port = addr_port; + dev->data_port = data_port; + + if (dev->addr_port) + io_sethandler(dev->addr_port, 1, it86x1f_read_addr, NULL, NULL, it86x1f_write_addr, NULL, NULL, dev); + if (dev->data_port) + io_sethandler(dev->data_port, 1, it86x1f_read_data, NULL, NULL, it86x1f_write_data, NULL, NULL, dev); +} + +static void +it86x1f_write_unlock(UNUSED(uint16_t port), uint8_t val, void *priv) +{ + it86x1f_t *dev = (it86x1f_t *) priv; + + it86x1f_log("IT86x1F: write_unlock(%04X, %02X)\n", port, val); + + if (!dev->locked) + dev->unlock_pos = 0; + + switch (dev->unlock_pos++) { + case 0: + if (val != (dev->unlock_id >> 8)) + dev->unlock_pos = 0; + break; + + case 1: + if (val != (dev->unlock_id & 0xff)) + dev->unlock_pos = 0; + break; + + case 2: + if ((val != 0x55) && (val != 0xaa)) + dev->unlock_pos = 0; + else + dev->unlock_val = val; + break; + + case 3: + switch ((dev->unlock_val << 8) | val) { + case 0x5555: + it86x1f_remap(dev, 0x3f0, 0x3f1); + break; + + case 0x55aa: + it86x1f_remap(dev, 0x3bd, 0x3bf); + break; + + case 0xaa55: + it86x1f_remap(dev, 0x370, 0x371); + break; + + default: + it86x1f_remap(dev, 0, 0); + break; + } + dev->unlock_pos = 0; + break; + } +} + +void +it86x1f_reset(it86x1f_t *dev) +{ + it86x1f_log("IT86x1F: reset()\n"); + + fdc_reset(dev->fdc); + + serial_remove(dev->uart[0]); + + serial_remove(dev->uart[1]); + + lpt1_remove(); + + isapnp_enable_card(dev->pnp_card, ISAPNP_CARD_DISABLE); + + dev->locked = 1; + + isapnp_reset_card(dev->pnp_card); +} + +static void +it86x1f_close(void *priv) +{ + it86x1f_t *dev = (it86x1f_t *) priv; + + it86x1f_log("IT86x1F: close()\n"); + + free(dev); +} + +static void * +it86x1f_init(UNUSED(const device_t *info)) +{ + it86x1f_t *dev = (it86x1f_t *) malloc(sizeof(it86x1f_t)); + memset(dev, 0, sizeof(it86x1f_t)); + + uint8_t i; + for (i = 0; i < (sizeof(it86x1f_models) / sizeof(it86x1f_models[0])); i++) { + if (it86x1f_models[i].chip_id == info->local) + break; + } + if (i >= (sizeof(it86x1f_models) / sizeof(it86x1f_models[0]))) { + fatal("IT86x1F: Unknown type %04X selected\n", info->local); + return NULL; + } + it86x1f_log("IT86x1F: init(%04X)\n", info->local); + + /* Let the resource data parser figure out the ROM size. */ + dev->pnp_card = isapnp_add_card(it86x1f_models[i].pnp_rom, -1, it86x1f_models[i].pnp_config_changed, NULL, it86x1f_pnp_read_vendor_reg, it86x1f_pnp_write_vendor_reg, dev); + for (uint8_t j = 0; it86x1f_models[i].pnp_defaults[j].activate != (uint8_t) -1; j++) + isapnp_set_device_defaults(dev->pnp_card, j, &it86x1f_models[i].pnp_defaults[j]); + + 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->gameport = gameport_add(&gameport_sio_device); + + dev->instance = device_get_instance(); + dev->gpio_ldn = it86x1f_models[i].gpio_ldn; + CHIP_ID = it86x1f_models[i].chip_id; + dev->unlock_id = it86x1f_models[i].unlock_id; + io_sethandler(0x279, 1, NULL, NULL, NULL, it86x1f_write_unlock, NULL, NULL, dev); + + it86x1f_reset(dev); + + return dev; +} + +const device_t it8661f_device = { + .name = "ITE IT8661F Super I/O", + .internal_name = "it8661f", + .flags = 0, + .local = ITE_IT8661F, + .init = it86x1f_init, + .close = it86x1f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t it8671f_device = { + .name = "ITE IT8671F Super I/O", + .internal_name = "it8671f", + .flags = 0, + .local = ITE_IT8671F, + .init = it86x1f_init, + .close = it86x1f_close, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index e22e5c289..eea036f7b 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -633,7 +633,7 @@ DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm SIOOBJ := sio_acc3221.o sio_ali5123.o \ sio_f82c710.o sio_82091aa.o sio_fdc37c6xx.o \ sio_fdc37c67x.o sio_fdc37c669.o sio_fdc37c93x.o sio_fdc37m60x.o \ - sio_it8661f.o \ + sio_it86x1f.o \ sio_pc87306.o sio_pc87307.o sio_pc87309.o sio_pc87310.o sio_pc87311.o sio_pc87332.o \ sio_prime3b.o sio_prime3c.o \ sio_w83787f.o \