Rewrite IT8661F and add IT8671F

This commit is contained in:
RichardG867
2023-10-23 15:50:19 -03:00
parent 53bb97ab9a
commit 3d65f69949
5 changed files with 865 additions and 355 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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 <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#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
};

862
src/sio/sio_it86x1f.c Normal file
View File

@@ -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, <richardg867@gmail.com>
*
* Copyright 2023 RichardG.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#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
};

View File

@@ -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 \