Conflict resolution.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -209,9 +209,9 @@ i82091aa_write(uint16_t port, uint8_t val, void *priv)
|
||||
uint8_t
|
||||
i82091aa_read(uint16_t port, void *priv)
|
||||
{
|
||||
i82091aa_t *dev = (i82091aa_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t index;
|
||||
const i82091aa_t *dev = (i82091aa_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t index;
|
||||
|
||||
index = (port & 1) ? 0 : 1;
|
||||
|
||||
|
||||
@@ -416,7 +416,7 @@ acc3221_write(uint16_t addr, uint8_t val, void *priv)
|
||||
static uint8_t
|
||||
acc3221_read(uint16_t addr, void *priv)
|
||||
{
|
||||
acc3221_t *dev = (acc3221_t *) priv;
|
||||
const acc3221_t *dev = (acc3221_t *) priv;
|
||||
|
||||
if (!(addr & 1))
|
||||
return dev->reg_idx;
|
||||
|
||||
@@ -428,10 +428,10 @@ ali5123_write(uint16_t port, uint8_t val, void *priv)
|
||||
static uint8_t
|
||||
ali5123_read(uint16_t port, void *priv)
|
||||
{
|
||||
ali5123_t *dev = (ali5123_t *) priv;
|
||||
uint8_t index = (port & 1) ? 0 : 1;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t cur_ld;
|
||||
const ali5123_t *dev = (ali5123_t *) priv;
|
||||
uint8_t index = (port & 1) ? 0 : 1;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t cur_ld;
|
||||
|
||||
if (dev->locked) {
|
||||
if (index)
|
||||
|
||||
@@ -47,7 +47,7 @@ sio_detect_write(uint16_t port, uint8_t val, void *priv)
|
||||
static uint8_t
|
||||
sio_detect_read(uint16_t port, void *priv)
|
||||
{
|
||||
sio_detect_t *dev = (sio_detect_t *) priv;
|
||||
const sio_detect_t *dev = (sio_detect_t *) priv;
|
||||
|
||||
pclog("sio_detect_read : port=%04x = %02X\n", port, dev->regs[port & 1]);
|
||||
|
||||
|
||||
@@ -18,11 +18,9 @@
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
|
||||
* Eluan Costa Miranda <eluancm@gmail.com>
|
||||
* Authors: Eluan Costa Miranda <eluancm@gmail.com>
|
||||
* Lubomir Rintel <lkundrak@v3.sk>
|
||||
*
|
||||
* Copyright 2020 Sarah Walker.
|
||||
* Copyright 2020 Eluan Costa Miranda.
|
||||
* Copyright 2021 Lubomir Rintel.
|
||||
*/
|
||||
@@ -230,8 +228,8 @@ f82c606_update_ports(upc_t *dev, int set)
|
||||
static uint8_t
|
||||
f82c710_config_read(uint16_t port, void *priv)
|
||||
{
|
||||
upc_t *dev = (upc_t *) priv;
|
||||
uint8_t temp = 0xff;
|
||||
const upc_t *dev = (upc_t *) priv;
|
||||
uint8_t temp = 0xff;
|
||||
|
||||
if (dev->configuration_mode) {
|
||||
if (port == dev->cri_addr) {
|
||||
|
||||
@@ -12,13 +12,15 @@
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2016-2024 Miran Grca.
|
||||
*/
|
||||
#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/io.h>
|
||||
#include <86box/timer.h>
|
||||
@@ -45,35 +47,67 @@ typedef struct fdc37c669_t {
|
||||
|
||||
static int next_id = 0;
|
||||
|
||||
static uint16_t
|
||||
make_port(fdc37c669_t *dev, uint8_t reg)
|
||||
#ifdef ENABLE_FDC37C669_LOG
|
||||
int fdc37c669_do_log = ENABLE_FDC37C669_LOG;
|
||||
|
||||
static void
|
||||
fdc37c669_log(const char *fmt, ...)
|
||||
{
|
||||
uint16_t p = 0;
|
||||
uint16_t mask = 0;
|
||||
va_list ap;
|
||||
|
||||
switch (reg) {
|
||||
case 0x20:
|
||||
case 0x21:
|
||||
case 0x22:
|
||||
mask = 0xfc;
|
||||
break;
|
||||
case 0x23:
|
||||
mask = 0xff;
|
||||
break;
|
||||
case 0x24:
|
||||
case 0x25:
|
||||
mask = 0xfe;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
if (fdc37c669_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define fdc37c669_log(fmt, ...)
|
||||
#endif
|
||||
|
||||
p = ((uint16_t) (dev->regs[reg] & mask)) << 2;
|
||||
if (reg == 0x22)
|
||||
p |= 6;
|
||||
static void
|
||||
fdc37c669_fdc_handler(fdc37c669_t *dev)
|
||||
{
|
||||
fdc_remove(dev->fdc);
|
||||
if (dev->regs[0x20] & 0xc0)
|
||||
fdc_set_base(dev->fdc, ((uint16_t) dev->regs[0x20]) << 2);
|
||||
}
|
||||
|
||||
return p;
|
||||
static void
|
||||
fdc37c669_uart_handler(fdc37c669_t *dev, uint8_t uart)
|
||||
{
|
||||
uint8_t uart_reg = 0x24 + uart;
|
||||
uint8_t pwrdn_mask = 0x08 << (uart << 2);
|
||||
uint8_t uart_shift = ((uart ^ 1) << 2);
|
||||
|
||||
serial_remove(dev->uart[uart]);
|
||||
if ((dev->regs[0x02] & pwrdn_mask) && (dev->regs[uart_reg] & 0xc0))
|
||||
serial_setup(dev->uart[0], ((uint16_t) dev->regs[0x24]) << 2,
|
||||
(dev->regs[0x28] >> uart_shift) & 0x0f);
|
||||
}
|
||||
|
||||
static double
|
||||
fdc37c669_uart_get_clock_src(fdc37c669_t *dev, uint8_t uart)
|
||||
{
|
||||
double clock_srcs[4] = { 24000000.0 / 13.0, 24000000.0 / 12.0, 24000000.0 / 3.0, 24000000.0 / 3.0 };
|
||||
double ret;
|
||||
uint8_t clock_src_0 = !!(dev->regs[0x04] & (0x10 << uart));
|
||||
uint8_t clock_src_1 = !!(dev->regs[0x0c] & (0x40 << uart));
|
||||
uint8_t clock_src = clock_src_0 | (clock_src_1 << 1);
|
||||
|
||||
ret = clock_srcs[clock_src];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
fdc37c669_lpt_handler(fdc37c669_t *dev)
|
||||
{
|
||||
uint8_t mask = ~(dev->regs[0x04] & 0x01);
|
||||
|
||||
lpt_port_remove(dev->id);
|
||||
if ((dev->regs[0x01] & 0x04) && (dev->regs[0x23] >= 0x40))
|
||||
lpt_port_init(dev->id, ((uint16_t) (dev->regs[0x23] & mask)) << 2);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -81,149 +115,153 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
fdc37c669_t *dev = (fdc37c669_t *) priv;
|
||||
uint8_t index = (port & 1) ? 0 : 1;
|
||||
uint8_t valxor = 0;
|
||||
uint8_t max = 42;
|
||||
uint8_t valxor = val ^ dev->regs[dev->cur_reg];
|
||||
|
||||
fdc37c669_log("[%04X:%08X] [W] %04X = %02X (%i, %i)\n", CS, cpu_state.pc, port, val,
|
||||
dev->tries, dev->locked);
|
||||
|
||||
if (index) {
|
||||
if ((val == 0x55) && !dev->locked) {
|
||||
if (dev->tries) {
|
||||
dev->tries = (dev->tries + 1) & 1;
|
||||
|
||||
if (!dev->tries)
|
||||
dev->locked = 1;
|
||||
dev->tries = 0;
|
||||
} else
|
||||
dev->tries++;
|
||||
} else {
|
||||
if (dev->locked) {
|
||||
if (val < max)
|
||||
dev->cur_reg = val;
|
||||
if (val == 0xaa)
|
||||
dev->locked = 0;
|
||||
} else {
|
||||
if (dev->tries)
|
||||
dev->tries = 0;
|
||||
}
|
||||
else
|
||||
dev->cur_reg = val;
|
||||
} else
|
||||
dev->tries = 0;
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (dev->locked) {
|
||||
if ((dev->cur_reg < 0x18) && (dev->rw_locked))
|
||||
return;
|
||||
if ((dev->cur_reg >= 0x26) && (dev->cur_reg <= 0x27))
|
||||
return;
|
||||
if (dev->cur_reg == 0x29)
|
||||
return;
|
||||
valxor = val ^ dev->regs[dev->cur_reg];
|
||||
} else if (!dev->rw_locked || (dev->cur_reg > 0x0f)) switch (dev->cur_reg) {
|
||||
case 0x00:
|
||||
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x74) | (val & 0x8b);
|
||||
if (!dev->id && (valxor & 8))
|
||||
fdc_set_power_down(dev->fdc, !(val & 0x08));
|
||||
break;
|
||||
case 0x01:
|
||||
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x73) | (val & 0x8c);
|
||||
if (valxor & 0x04)
|
||||
fdc37c669_lpt_handler(dev);
|
||||
if (valxor & 0x80)
|
||||
dev->rw_locked = !(val & 0x80);
|
||||
break;
|
||||
case 0x02:
|
||||
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x77) | (val & 0x88);
|
||||
if (valxor & 0x08)
|
||||
fdc37c669_uart_handler(dev, 0);
|
||||
if (valxor & 0x80)
|
||||
fdc37c669_uart_handler(dev, 1);
|
||||
break;
|
||||
case 0x03:
|
||||
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x08) | (val & 0xf7);
|
||||
if (!dev->id && (valxor & 0x02))
|
||||
fdc_update_enh_mode(dev->fdc, !!(val & 0x02));
|
||||
break;
|
||||
case 0x04:
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
} else
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dev->cur_reg) {
|
||||
case 0:
|
||||
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));
|
||||
}
|
||||
if (valxor & 0x03)
|
||||
fdc37c669_lpt_handler(dev);
|
||||
if (valxor & 0x10)
|
||||
serial_set_clock_src(dev->uart[0], fdc37c669_uart_get_clock_src(dev, 0));
|
||||
if (valxor & 0x20)
|
||||
serial_set_clock_src(dev->uart[1], fdc37c669_uart_get_clock_src(dev, 1));
|
||||
break;
|
||||
case 1:
|
||||
if (valxor & 4) {
|
||||
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;
|
||||
break;
|
||||
case 2:
|
||||
if (valxor & 8) {
|
||||
serial_remove(dev->uart[0]);
|
||||
if ((dev->regs[2] & 8) && (dev->regs[0x24] >= 0x40))
|
||||
serial_setup(dev->uart[0], make_port(dev, 0x24), (dev->regs[0x28] & 0xf0) >> 4);
|
||||
}
|
||||
if (valxor & 0x80) {
|
||||
serial_remove(dev->uart[1]);
|
||||
if ((dev->regs[2] & 0x80) && (dev->regs[0x25] >= 0x40))
|
||||
serial_setup(dev->uart[1], make_port(dev, 0x25), dev->regs[0x28] & 0x0f);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (!dev->id && (valxor & 2))
|
||||
fdc_update_enh_mode(dev->fdc, (val & 2) ? 1 : 0);
|
||||
break;
|
||||
case 5:
|
||||
case 0x05:
|
||||
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x83) | (val & 0x7c);
|
||||
if (!dev->id && (valxor & 0x18))
|
||||
fdc_update_densel_force(dev->fdc, (val & 0x18) >> 3);
|
||||
if (!dev->id && (valxor & 0x20))
|
||||
fdc_set_swap(dev->fdc, (val & 0x20) >> 5);
|
||||
break;
|
||||
case 0xB:
|
||||
if (!dev->id && (valxor & 3))
|
||||
fdc_update_rwc(dev->fdc, 0, val & 3);
|
||||
if (!dev->id && (valxor & 0xC))
|
||||
fdc_update_rwc(dev->fdc, 1, (val & 0xC) >> 2);
|
||||
case 0x06:
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
break;
|
||||
case 0x07:
|
||||
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x06) | (val & 0xf9);
|
||||
break;
|
||||
case 0x08:
|
||||
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x0f) | (val & 0xf0);
|
||||
break;
|
||||
case 0x09:
|
||||
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x38) | (val & 0xc7);
|
||||
break;
|
||||
case 0x0a:
|
||||
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0xf0) | (val & 0x0f);
|
||||
break;
|
||||
case 0x0b:
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
if (!dev->id && (valxor & 0x03))
|
||||
fdc_update_rwc(dev->fdc, 0, val & 0x03);
|
||||
if (!dev->id && (valxor & 0x0c))
|
||||
fdc_update_rwc(dev->fdc, 1, (val & 0x0c) >> 2);
|
||||
break;
|
||||
case 0x0c:
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
if (valxor & 0x40)
|
||||
serial_set_clock_src(dev->uart[0], fdc37c669_uart_get_clock_src(dev, 0));
|
||||
if (valxor & 0x80)
|
||||
serial_set_clock_src(dev->uart[1], fdc37c669_uart_get_clock_src(dev, 1));
|
||||
break;
|
||||
case 0x0f:
|
||||
case 0x12 ... 0x1f:
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
break;
|
||||
case 0x10:
|
||||
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x07) | (val & 0xf8);
|
||||
break;
|
||||
case 0x11:
|
||||
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0xfc) | (val & 0x03);
|
||||
break;
|
||||
case 0x20:
|
||||
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));
|
||||
}
|
||||
dev->regs[dev->cur_reg] = val & 0xfc;
|
||||
if (!dev->id && (valxor & 0xfc))
|
||||
fdc37c669_fdc_handler(dev);
|
||||
break;
|
||||
case 0x21:
|
||||
dev->regs[dev->cur_reg] = val & 0xfc;
|
||||
break;
|
||||
case 0x22:
|
||||
dev->regs[dev->cur_reg] = (dev->regs[dev->cur_reg] & 0x03) | (val & 0xfc);
|
||||
break;
|
||||
case 0x23:
|
||||
if (valxor) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
if (valxor)
|
||||
fdc37c669_lpt_handler(dev);
|
||||
break;
|
||||
case 0x24:
|
||||
if (valxor & 0xfe) {
|
||||
serial_remove(dev->uart[0]);
|
||||
if ((dev->regs[2] & 8) && (dev->regs[0x24] >= 0x40))
|
||||
serial_setup(dev->uart[0], make_port(dev, 0x24), (dev->regs[0x28] & 0xf0) >> 4);
|
||||
}
|
||||
dev->regs[dev->cur_reg] = val & 0xfe;
|
||||
if (valxor & 0xfe)
|
||||
fdc37c669_uart_handler(dev, 0);
|
||||
break;
|
||||
case 0x25:
|
||||
if (valxor & 0xfe) {
|
||||
serial_remove(dev->uart[1]);
|
||||
if ((dev->regs[2] & 0x80) && (dev->regs[0x25] >= 0x40))
|
||||
serial_setup(dev->uart[1], make_port(dev, 0x25), dev->regs[0x28] & 0x0f);
|
||||
}
|
||||
dev->regs[dev->cur_reg] = val & 0xfe;
|
||||
if (valxor & 0xfe)
|
||||
fdc37c669_uart_handler(dev, 1);
|
||||
break;
|
||||
case 0x26:
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
if (valxor & 0xf0)
|
||||
fdc_set_dma_ch(dev->fdc, val >> 4);
|
||||
break;
|
||||
case 0x27:
|
||||
if (valxor & 0xf) {
|
||||
if (dev->id)
|
||||
lpt2_irq(val & 0xf);
|
||||
else
|
||||
lpt1_irq(val & 0xf);
|
||||
}
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
if (valxor & 0xf0)
|
||||
fdc_set_irq(dev->fdc, val >> 4);
|
||||
if (valxor & 0x0f)
|
||||
lpt_port_irq(dev->id, val & 0x0f);
|
||||
break;
|
||||
case 0x28:
|
||||
if (valxor & 0xf) {
|
||||
serial_remove(dev->uart[1]);
|
||||
if ((dev->regs[2] & 0x80) && (dev->regs[0x25] >= 0x40))
|
||||
serial_setup(dev->uart[1], make_port(dev, 0x25), dev->regs[0x28] & 0x0f);
|
||||
}
|
||||
if (valxor & 0xf0) {
|
||||
serial_remove(dev->uart[0]);
|
||||
if ((dev->regs[2] & 8) && (dev->regs[0x24] >= 0x40))
|
||||
serial_setup(dev->uart[0], make_port(dev, 0x24), (dev->regs[0x28] & 0xf0) >> 4);
|
||||
}
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
if (valxor & 0xf0)
|
||||
fdc37c669_uart_handler(dev, 0);
|
||||
if (valxor & 0x0f)
|
||||
fdc37c669_uart_handler(dev, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
case 0x29:
|
||||
dev->regs[dev->cur_reg] = val & 0x0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -231,30 +269,30 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv)
|
||||
static uint8_t
|
||||
fdc37c669_read(uint16_t port, void *priv)
|
||||
{
|
||||
fdc37c669_t *dev = (fdc37c669_t *) priv;
|
||||
uint8_t index = (port & 1) ? 0 : 1;
|
||||
uint8_t ret = 0xff;
|
||||
const fdc37c669_t *dev = (fdc37c669_t *) priv;
|
||||
uint8_t index = (port & 1) ? 0 : 1;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if (dev->locked) {
|
||||
if (index)
|
||||
ret = dev->cur_reg;
|
||||
else if ((dev->cur_reg >= 0x18) || !dev->rw_locked)
|
||||
else if (!dev->rw_locked || (dev->cur_reg > 0x0f))
|
||||
ret = dev->regs[dev->cur_reg];
|
||||
}
|
||||
|
||||
fdc37c669_log("[%04X:%08X] [R] %04X = %02X (%i, %i)\n", CS, cpu_state.pc, port, ret,
|
||||
dev->tries, dev->locked);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
fdc37c669_reset(fdc37c669_t *dev)
|
||||
fdc37c669_reset(void *priv)
|
||||
{
|
||||
serial_remove(dev->uart[0]);
|
||||
serial_setup(dev->uart[0], COM1_ADDR, COM1_IRQ);
|
||||
fdc37c669_t *dev = (fdc37c669_t *) priv;
|
||||
|
||||
serial_remove(dev->uart[1]);
|
||||
serial_setup(dev->uart[1], COM2_ADDR, COM2_IRQ);
|
||||
memset(dev->regs, 0x00, 42);
|
||||
|
||||
memset(dev->regs, 0, 42);
|
||||
dev->regs[0x00] = 0x28;
|
||||
dev->regs[0x01] = 0x9c;
|
||||
dev->regs[0x02] = 0x88;
|
||||
@@ -262,32 +300,23 @@ fdc37c669_reset(fdc37c669_t *dev)
|
||||
dev->regs[0x06] = 0xff;
|
||||
dev->regs[0x0d] = 0x03;
|
||||
dev->regs[0x0e] = 0x02;
|
||||
dev->regs[0x1e] = 0x80; /* Gameport controller. */
|
||||
dev->regs[0x20] = (FDC_PRIMARY_ADDR >> 2) & 0xfc;
|
||||
dev->regs[0x21] = (0x1f0 >> 2) & 0xfc;
|
||||
dev->regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1;
|
||||
dev->regs[0x1e] = 0x3c; /* Gameport controller. */
|
||||
dev->regs[0x20] = 0x3c;
|
||||
dev->regs[0x21] = 0x3c;
|
||||
dev->regs[0x22] = 0x3d;
|
||||
|
||||
if (dev->id == 1) {
|
||||
dev->regs[0x23] = (LPT2_ADDR >> 2);
|
||||
|
||||
lpt2_remove();
|
||||
lpt2_init(LPT2_ADDR);
|
||||
|
||||
dev->regs[0x24] = (COM3_ADDR >> 2) & 0xfe;
|
||||
dev->regs[0x25] = (COM4_ADDR >> 2) & 0xfe;
|
||||
} else {
|
||||
fdc_reset(dev->fdc);
|
||||
|
||||
lpt1_remove();
|
||||
lpt1_init(LPT1_ADDR);
|
||||
|
||||
dev->regs[0x23] = (LPT1_ADDR >> 2);
|
||||
|
||||
dev->regs[0x24] = (COM1_ADDR >> 2) & 0xfe;
|
||||
dev->regs[0x25] = (COM2_ADDR >> 2) & 0xfe;
|
||||
fdc37c669_fdc_handler(dev);
|
||||
}
|
||||
dev->regs[0x26] = (2 << 4) | 3;
|
||||
dev->regs[0x27] = (6 << 4) | (dev->id ? 5 : 7);
|
||||
dev->regs[0x28] = (4 << 4) | 3;
|
||||
|
||||
fdc37c669_uart_handler(dev, 0);
|
||||
serial_set_clock_src(dev->uart[0], fdc37c669_uart_get_clock_src(dev, 0));
|
||||
|
||||
fdc37c669_uart_handler(dev, 1);
|
||||
serial_set_clock_src(dev->uart[1], fdc37c669_uart_get_clock_src(dev, 1));
|
||||
|
||||
fdc37c669_lpt_handler(dev);
|
||||
|
||||
dev->locked = 0;
|
||||
dev->rw_locked = 0;
|
||||
@@ -317,8 +346,8 @@ fdc37c669_init(const device_t *info)
|
||||
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 ? FDC_SECONDARY_ADDR : (next_id ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR), 0x0002,
|
||||
fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, dev);
|
||||
io_sethandler(info->local ? FDC_SECONDARY_ADDR : (next_id ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR),
|
||||
0x0002, fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, dev);
|
||||
|
||||
fdc37c669_reset(dev);
|
||||
|
||||
@@ -334,7 +363,7 @@ const device_t fdc37c669_device = {
|
||||
.local = 0,
|
||||
.init = fdc37c669_init,
|
||||
.close = fdc37c669_close,
|
||||
.reset = NULL,
|
||||
.reset = fdc37c669_reset,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
@@ -348,7 +377,7 @@ const device_t fdc37c669_370_device = {
|
||||
.local = 1,
|
||||
.init = fdc37c669_init,
|
||||
.close = fdc37c669_close,
|
||||
.reset = NULL,
|
||||
.reset = fdc37c669_reset,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
|
||||
@@ -71,7 +71,7 @@ make_port(fdc37c67x_t *dev, uint8_t ld)
|
||||
static uint8_t
|
||||
fdc37c67x_auxio_read(UNUSED(uint16_t port), void *priv)
|
||||
{
|
||||
fdc37c67x_t *dev = (fdc37c67x_t *) priv;
|
||||
const fdc37c67x_t *dev = (fdc37c67x_t *) priv;
|
||||
|
||||
return dev->auxio_reg;
|
||||
}
|
||||
@@ -87,8 +87,8 @@ fdc37c67x_auxio_write(UNUSED(uint16_t port), uint8_t val, void *priv)
|
||||
static uint8_t
|
||||
fdc37c67x_gpio_read(uint16_t port, void *priv)
|
||||
{
|
||||
fdc37c67x_t *dev = (fdc37c67x_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
const fdc37c67x_t *dev = (fdc37c67x_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
ret = dev->gpio_regs[port & 1];
|
||||
|
||||
@@ -316,6 +316,7 @@ fdc37c67x_write(uint16_t port, uint8_t val, void *priv)
|
||||
case 0x26:
|
||||
case 0x27:
|
||||
fdc37c67x_sio_handler(dev);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -11,10 +11,8 @@
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2020 Sarah Walker.
|
||||
* Copyright 2016-2020 Miran Grca.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
@@ -230,8 +228,8 @@ fdc37c6xx_write(uint16_t port, uint8_t val, void *priv)
|
||||
static uint8_t
|
||||
fdc37c6xx_read(uint16_t port, void *priv)
|
||||
{
|
||||
fdc37c6xx_t *dev = (fdc37c6xx_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
const fdc37c6xx_t *dev = (fdc37c6xx_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if (dev->tries == 2) {
|
||||
if (port == 0x3f1)
|
||||
|
||||
@@ -93,7 +93,7 @@ make_port_sec(fdc37c93x_t *dev, uint8_t ld)
|
||||
static uint8_t
|
||||
fdc37c93x_auxio_read(UNUSED(uint16_t port), void *priv)
|
||||
{
|
||||
fdc37c93x_t *dev = (fdc37c93x_t *) priv;
|
||||
const fdc37c93x_t *dev = (fdc37c93x_t *) priv;
|
||||
|
||||
return dev->auxio_reg;
|
||||
}
|
||||
@@ -109,8 +109,8 @@ fdc37c93x_auxio_write(UNUSED(uint16_t port), uint8_t val, void *priv)
|
||||
static uint8_t
|
||||
fdc37c93x_gpio_read(uint16_t port, void *priv)
|
||||
{
|
||||
fdc37c93x_t *dev = (fdc37c93x_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
const fdc37c93x_t *dev = (fdc37c93x_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
ret = dev->gpio_regs[port & 1];
|
||||
|
||||
@@ -257,8 +257,8 @@ fdc37c93x_gpio_handler(fdc37c93x_t *dev)
|
||||
static uint8_t
|
||||
fdc37c93x_access_bus_read(uint16_t port, void *priv)
|
||||
{
|
||||
access_bus_t *dev = (access_bus_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
const access_bus_t *dev = (access_bus_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
switch (port & 3) {
|
||||
case 0:
|
||||
|
||||
@@ -163,8 +163,8 @@ fdc37m60x_write(uint16_t addr, uint8_t val, void *priv)
|
||||
static uint8_t
|
||||
fdc37m60x_read(uint16_t addr, void *priv)
|
||||
{
|
||||
fdc37m60x_t *dev = (fdc37m60x_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
const fdc37m60x_t *dev = (fdc37m60x_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if (addr & 1)
|
||||
ret = (INDEX >= 0x30) ? dev->device_regs[CURRENT_LOGICAL_DEVICE][INDEX] : dev->regs[INDEX];
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
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
|
||||
};
|
||||
871
src/sio/sio_it86x1f.c
Normal file
871
src/sio/sio_it86x1f.c
Normal file
@@ -0,0 +1,871 @@
|
||||
/*
|
||||
* 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 <inttypes.h>
|
||||
#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/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;
|
||||
uint8_t effective_ldn;
|
||||
|
||||
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. */
|
||||
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]))) {
|
||||
#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)
|
||||
fatal("IT86x1F: Unknown type %04" PRIX64 " selected\n", info->local);
|
||||
#else
|
||||
fatal("IT86x1F: Unknown type %04X selected\n", info->local);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)
|
||||
it86x1f_log("IT86x1F: init(%04" PRIX64 ")\n", info->local);
|
||||
#else
|
||||
it86x1f_log("IT86x1F: init(%04X)\n", info->local);
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
};
|
||||
@@ -35,11 +35,13 @@
|
||||
#include <86box/fdc.h>
|
||||
#include <86box/sio.h>
|
||||
#include <86box/plat_unused.h>
|
||||
#include <86box/machine.h>
|
||||
|
||||
typedef struct pc87306_t {
|
||||
uint8_t tries;
|
||||
uint8_t regs[29];
|
||||
uint8_t gpio[2];
|
||||
uint16_t gpioba;
|
||||
int cur_reg;
|
||||
fdc_t *fdc;
|
||||
serial_t *uart[2];
|
||||
@@ -50,37 +52,66 @@ static void
|
||||
pc87306_gpio_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
pc87306_t *dev = (pc87306_t *) priv;
|
||||
uint32_t gpio = 0xffff0000;
|
||||
|
||||
dev->gpio[port & 1] = val;
|
||||
dev->gpio[port & 0x0001] = val;
|
||||
|
||||
if (port & 0x0001) {
|
||||
gpio |= ((uint32_t) val) << 8;
|
||||
gpio |= dev->gpio[0];
|
||||
} else {
|
||||
gpio |= ((uint32_t) dev->gpio[1]) << 8;
|
||||
gpio |= val;
|
||||
}
|
||||
|
||||
(void) machine_handle_gpio(1, gpio);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
pc87306_gpio_read(uint16_t port, void *priv)
|
||||
{
|
||||
pc87306_t *dev = (pc87306_t *) priv;
|
||||
uint32_t ret = machine_handle_gpio(0, 0xffffffff);
|
||||
|
||||
return dev->gpio[port & 1];
|
||||
if (port & 0x0001)
|
||||
ret = (ret >> 8) & 0xff;
|
||||
else
|
||||
ret &= 0xff;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
pc87306_gpio_remove(pc87306_t *dev)
|
||||
{
|
||||
io_removehandler(dev->regs[0x0f] << 2, 0x0001,
|
||||
pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev);
|
||||
io_removehandler((dev->regs[0x0f] << 2) + 1, 0x0001,
|
||||
pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev);
|
||||
if (dev->gpioba != 0x0000) {
|
||||
io_removehandler(dev->gpioba, 0x0001,
|
||||
pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev);
|
||||
io_removehandler(dev->gpioba + 1, 0x0001,
|
||||
pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pc87306_gpio_init(pc87306_t *dev)
|
||||
{
|
||||
if ((dev->regs[0x12]) & 0x10)
|
||||
io_sethandler(dev->regs[0x0f] << 2, 0x0001,
|
||||
pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev);
|
||||
dev->gpioba = ((uint16_t) dev->regs[0x0f]) << 2;
|
||||
|
||||
if ((dev->regs[0x12]) & 0x20)
|
||||
io_sethandler((dev->regs[0x0f] << 2) + 1, 0x0001,
|
||||
pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev);
|
||||
if (dev->gpioba != 0x0000) {
|
||||
if ((dev->regs[0x12]) & 0x10)
|
||||
io_sethandler(dev->gpioba, 0x0001,
|
||||
pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev);
|
||||
|
||||
if ((dev->regs[0x12]) & 0x20)
|
||||
io_sethandler(dev->gpioba + 1, 0x0001,
|
||||
pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pc87306_gpio_handler(pc87306_t *dev)
|
||||
{
|
||||
pc87306_gpio_remove(dev);
|
||||
pc87306_gpio_init(dev);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -222,8 +253,6 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
||||
if ((dev->cur_reg <= 28) && (dev->cur_reg != 8)) {
|
||||
if (dev->cur_reg == 0)
|
||||
val &= 0x5f;
|
||||
if (((dev->cur_reg == 0x0F) || (dev->cur_reg == 0x12)) && valxor)
|
||||
pc87306_gpio_remove(dev);
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
} else
|
||||
return;
|
||||
@@ -234,7 +263,7 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
||||
}
|
||||
|
||||
switch (dev->cur_reg) {
|
||||
case 0:
|
||||
case 0x00:
|
||||
if (valxor & 1) {
|
||||
lpt1_remove();
|
||||
if ((val & 1) && !(dev->regs[2] & 1))
|
||||
@@ -256,7 +285,7 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
||||
fdc_set_base(dev->fdc, (val & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 0x01:
|
||||
if (valxor & 3) {
|
||||
lpt1_remove();
|
||||
if ((dev->regs[0] & 1) && !(dev->regs[2] & 1))
|
||||
@@ -273,7 +302,7 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
||||
serial_handler(dev, 1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 0x02:
|
||||
if (valxor & 1) {
|
||||
lpt1_remove();
|
||||
serial_remove(dev->uart[0]);
|
||||
@@ -297,19 +326,31 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
||||
lpt1_handler(dev);
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
case 0x04:
|
||||
if (valxor & 0x80)
|
||||
nvr_lock_set(0x00, 256, !!(val & 0x80), dev->nvr);
|
||||
break;
|
||||
case 0x05:
|
||||
if (valxor & 0x08)
|
||||
nvr_at_handler(!!(val & 0x08), 0x0070, dev->nvr);
|
||||
if (valxor & 0x20)
|
||||
nvr_bank_set(0, !!(val & 0x20), dev->nvr);
|
||||
break;
|
||||
case 0x09:
|
||||
if (valxor & 0x44) {
|
||||
fdc_update_enh_mode(dev->fdc, (val & 4) ? 1 : 0);
|
||||
fdc_update_densel_polarity(dev->fdc, (val & 0x40) ? 1 : 0);
|
||||
}
|
||||
break;
|
||||
case 0xF:
|
||||
case 0x0f:
|
||||
if (valxor)
|
||||
pc87306_gpio_init(dev);
|
||||
pc87306_gpio_handler(dev);
|
||||
break;
|
||||
case 0x12:
|
||||
if (valxor & 0x01)
|
||||
nvr_wp_set(!!(val & 0x01), 0, dev->nvr);
|
||||
if (valxor & 0x30)
|
||||
pc87306_gpio_init(dev);
|
||||
pc87306_gpio_handler(dev);
|
||||
break;
|
||||
case 0x19:
|
||||
if (valxor) {
|
||||
@@ -368,8 +409,10 @@ pc87306_read(uint16_t port, void *priv)
|
||||
}
|
||||
|
||||
void
|
||||
pc87306_reset(pc87306_t *dev)
|
||||
pc87306_reset_common(void *priv)
|
||||
{
|
||||
pc87306_t *dev = (pc87306_t *) priv;
|
||||
|
||||
memset(dev->regs, 0, 29);
|
||||
|
||||
dev->regs[0x00] = 0x0B;
|
||||
@@ -383,9 +426,6 @@ pc87306_reset(pc87306_t *dev)
|
||||
dev->regs[0x12] = 0x30;
|
||||
dev->regs[0x19] = 0xEF;
|
||||
|
||||
dev->gpio[0] = 0xff;
|
||||
dev->gpio[1] = 0xfb;
|
||||
|
||||
/*
|
||||
0 = 360 rpm @ 500 kbps for 3.5"
|
||||
1 = Default, 300 rpm @ 500, 300, 250, 1000 kbps for 3.5"
|
||||
@@ -398,6 +438,22 @@ pc87306_reset(pc87306_t *dev)
|
||||
serial_handler(dev, 1);
|
||||
fdc_reset(dev->fdc);
|
||||
pc87306_gpio_init(dev);
|
||||
nvr_lock_set(0x00, 256, 0, dev->nvr);
|
||||
nvr_at_handler(0, 0x0070, dev->nvr);
|
||||
nvr_at_handler(1, 0x0070, dev->nvr);
|
||||
nvr_bank_set(0, 0, dev->nvr);
|
||||
nvr_wp_set(0, 0, dev->nvr);
|
||||
}
|
||||
|
||||
void
|
||||
pc87306_reset(void *priv)
|
||||
{
|
||||
pc87306_t *dev = (pc87306_t *) priv;
|
||||
|
||||
pc87306_gpio_write(0x0000, 0xff, dev);
|
||||
pc87306_gpio_write(0x0001, 0xff, dev);
|
||||
|
||||
pc87306_reset_common(dev);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -419,9 +475,11 @@ pc87306_init(UNUSED(const device_t *info))
|
||||
dev->uart[0] = device_add_inst(&ns16550_device, 1);
|
||||
dev->uart[1] = device_add_inst(&ns16550_device, 2);
|
||||
|
||||
// dev->nvr = device_add(&piix4_nvr_device);
|
||||
dev->nvr = device_add(&at_mb_nvr_device);
|
||||
|
||||
pc87306_reset(dev);
|
||||
dev->gpio[0] = dev->gpio[1] = 0xff;
|
||||
|
||||
pc87306_reset_common(dev);
|
||||
|
||||
io_sethandler(0x02e, 0x0002,
|
||||
pc87306_read, NULL, NULL, pc87306_write, NULL, NULL, dev);
|
||||
@@ -436,7 +494,7 @@ const device_t pc87306_device = {
|
||||
.local = 0,
|
||||
.init = pc87306_init,
|
||||
.close = pc87306_close,
|
||||
.reset = NULL,
|
||||
.reset = pc87306_reset,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
|
||||
@@ -67,11 +67,11 @@ pc87307_gpio_write(uint16_t port, uint8_t val, void *priv)
|
||||
uint8_t
|
||||
pc87307_gpio_read(uint16_t port, void *priv)
|
||||
{
|
||||
pc87307_t *dev = (pc87307_t *) priv;
|
||||
uint8_t pins = 0xff;
|
||||
uint8_t bank = ((port & 0xfffc) == dev->gpio_base2);
|
||||
uint8_t mask;
|
||||
uint8_t ret = dev->gpio[bank][port & 0x0003];
|
||||
const pc87307_t *dev = (pc87307_t *) priv;
|
||||
uint8_t pins = 0xff;
|
||||
uint8_t bank = ((port & 0xfffc) == dev->gpio_base2);
|
||||
uint8_t mask;
|
||||
uint8_t ret = dev->gpio[bank][port & 0x0003];
|
||||
|
||||
switch (port & 0x0003) {
|
||||
case 0x0000:
|
||||
@@ -139,7 +139,7 @@ pc87307_pm_write(uint16_t port, uint8_t val, void *priv)
|
||||
uint8_t
|
||||
pc87307_pm_read(uint16_t port, void *priv)
|
||||
{
|
||||
pc87307_t *dev = (pc87307_t *) priv;
|
||||
const pc87307_t *dev = (pc87307_t *) priv;
|
||||
|
||||
if (port & 1)
|
||||
return dev->pm[dev->pm_idx];
|
||||
@@ -456,9 +456,9 @@ pc87307_write(uint16_t port, uint8_t val, void *priv)
|
||||
uint8_t
|
||||
pc87307_read(uint16_t port, void *priv)
|
||||
{
|
||||
pc87307_t *dev = (pc87307_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t index;
|
||||
const pc87307_t *dev = (pc87307_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t index;
|
||||
|
||||
index = (port & 1) ? 0 : 1;
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ pc87309_pm_write(uint16_t port, uint8_t val, void *priv)
|
||||
uint8_t
|
||||
pc87309_pm_read(uint16_t port, void *priv)
|
||||
{
|
||||
pc87309_t *dev = (pc87309_t *) priv;
|
||||
const pc87309_t *dev = (pc87309_t *) priv;
|
||||
|
||||
if (port & 1)
|
||||
return dev->pm[dev->pm_idx];
|
||||
@@ -351,9 +351,9 @@ pc87309_write(uint16_t port, uint8_t val, void *priv)
|
||||
uint8_t
|
||||
pc87309_read(uint16_t port, void *priv)
|
||||
{
|
||||
pc87309_t *dev = (pc87309_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t index;
|
||||
const pc87309_t *dev = (pc87309_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t index;
|
||||
|
||||
index = (port & 1) ? 0 : 1;
|
||||
|
||||
|
||||
@@ -8,15 +8,13 @@
|
||||
*
|
||||
* Emulation of the NatSemi PC87310 Super I/O chip.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Tiseno100
|
||||
* EngiNerd <webmaster.crrc@yahoo.it>
|
||||
* EngiNerd, <webmaster.crrc@yahoo.it>
|
||||
* Tiseno100,
|
||||
*
|
||||
* Copyright 2020 Miran Grca.
|
||||
* Copyright 2020 Tiseno100
|
||||
* Copyright 2020-2024 Miran Grca.
|
||||
* Copyright 2021 EngiNerd.
|
||||
* Copyright 2020 Tiseno100.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
@@ -42,7 +40,8 @@
|
||||
#include <86box/sio.h>
|
||||
#include <86box/plat_unused.h>
|
||||
|
||||
#define HAS_IDE_FUNCTIONALITY dev->ide_function
|
||||
#define FLAG_IDE 0x00000001
|
||||
#define FLAG_ALI 0x00000002
|
||||
|
||||
#ifdef ENABLE_PC87310_LOG
|
||||
int pc87310_do_log = ENABLE_PC87310_LOG;
|
||||
@@ -64,8 +63,8 @@ pc87310_log(const char *fmt, ...)
|
||||
|
||||
typedef struct pc87310_t {
|
||||
uint8_t tries;
|
||||
uint8_t ide_function;
|
||||
uint8_t reg;
|
||||
uint8_t flags;
|
||||
uint8_t regs[2];
|
||||
fdc_t *fdc;
|
||||
serial_t *uart[2];
|
||||
} pc87310_t;
|
||||
@@ -83,7 +82,9 @@ lpt1_handler(pc87310_t *dev)
|
||||
* 10 278h
|
||||
* 11 disabled
|
||||
*/
|
||||
temp = dev->reg & 3;
|
||||
temp = dev->regs[1] & 0x03;
|
||||
|
||||
lpt1_remove();
|
||||
|
||||
switch (temp) {
|
||||
case 0:
|
||||
@@ -111,23 +112,59 @@ lpt1_handler(pc87310_t *dev)
|
||||
}
|
||||
|
||||
static void
|
||||
serial_handler(pc87310_t *dev, int uart)
|
||||
serial_handler(pc87310_t *dev)
|
||||
{
|
||||
int temp;
|
||||
/* bit 2: disable serial port 1
|
||||
* bit 3: disable serial port 2
|
||||
* bit 4: swap serial ports
|
||||
uint8_t temp, temp2 = 0x00;
|
||||
uint16_t base1 = 0x0000, base2 = 0x0000;
|
||||
uint8_t irq1, irq2;
|
||||
/* - Bit 2: Disable serial port 1;
|
||||
* - Bit 3: Disable serial port 2;
|
||||
* - Bit 4: Swap serial ports.
|
||||
*/
|
||||
temp = (dev->reg >> (2 + uart)) & 1;
|
||||
temp = (dev->regs[1] >> 2) & 0x07;
|
||||
|
||||
// current serial port is enabled
|
||||
if (!temp) {
|
||||
// configure serial port as COM2
|
||||
if (((dev->reg >> 4) & 1) ^ uart)
|
||||
serial_setup(dev->uart[uart], COM2_ADDR, COM2_IRQ);
|
||||
// configure serial port as COM1
|
||||
else
|
||||
serial_setup(dev->uart[uart], COM1_ADDR, COM1_IRQ);
|
||||
/* - Bits 1, 0: 0, 0 = Normal (3F8 and 2F8);
|
||||
* 0, 1 = 2E8 instead of 2F8;
|
||||
* 1, 0 = 3E8 instead of 3F8 and 2E8 instead of 2F8;
|
||||
* 1, 1 = 3E8 instead of 3F8.
|
||||
*
|
||||
* If we XOR bit 0 with bit 1, we get this:
|
||||
* 0, 0 = Normal (3F8 and 2F8);
|
||||
* 0, 1 = 2E8 instead of 2F8;
|
||||
* 1, 0 = 3E8 instead of 3F8;
|
||||
* 1, 1 = 3E8 instead of 3F8 and 2E8 instead of 2F8.
|
||||
*
|
||||
* Then they become simple toggle bits.
|
||||
* Therefore, we do this for easier operation.
|
||||
*/
|
||||
if (dev->flags & FLAG_ALI) {
|
||||
temp2 = dev->regs[0] & 0x03;
|
||||
temp2 ^= ((temp2 & 0x02) >> 1);
|
||||
}
|
||||
|
||||
serial_remove(dev->uart[0]);
|
||||
serial_remove(dev->uart[1]);
|
||||
|
||||
if (!(temp & 0x01)) {
|
||||
base1 = (temp & 0x04) ? COM2_ADDR : COM1_ADDR;
|
||||
if ((base1 == COM1_ADDR) && (temp2 & 0x02))
|
||||
base1 = 0x03e8;
|
||||
else if ((base1 == COM2_ADDR) && (temp2 & 0x01))
|
||||
base1 = 0x02e8;
|
||||
irq1 = (temp & 0x04) ? COM2_IRQ : COM1_IRQ;
|
||||
serial_setup(dev->uart[0], base1, irq1);
|
||||
pc87310_log("UART 1 at %04X, IRQ %i\n", base1, irq1);
|
||||
}
|
||||
|
||||
if (!(temp & 0x02)) {
|
||||
base2 = (temp & 0x04) ? COM1_ADDR : COM2_ADDR;
|
||||
if ((base2 == COM1_ADDR) && (temp2 & 0x02))
|
||||
base2 = 0x03e8;
|
||||
else if ((base2 == COM2_ADDR) && (temp2 & 0x01))
|
||||
base2 = 0x02e8;
|
||||
irq2 = (temp & 0x04) ? COM1_IRQ : COM2_IRQ;
|
||||
serial_setup(dev->uart[1], base2, irq2);
|
||||
pc87310_log("UART 2 at %04X, IRQ %i\n", base2, irq2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,61 +173,63 @@ pc87310_write(UNUSED(uint16_t port), uint8_t val, void *priv)
|
||||
{
|
||||
pc87310_t *dev = (pc87310_t *) priv;
|
||||
uint8_t valxor;
|
||||
uint8_t idx = (uint8_t) ((port & 0x0002) >> 1);
|
||||
|
||||
pc87310_log("[%04X:%08X] [W] %02X = %02X (%i)\n", CS, cpu_state.pc, port, val, dev->tries);
|
||||
|
||||
// second write to config register
|
||||
if (dev->tries) {
|
||||
valxor = val ^ dev->reg;
|
||||
dev->tries = 0;
|
||||
dev->reg = val;
|
||||
// first write to config register
|
||||
} else {
|
||||
/* Second write to config register. */
|
||||
valxor = val ^ dev->regs[idx];
|
||||
dev->tries = 0;
|
||||
dev->regs[idx] = val;
|
||||
|
||||
if (idx) {
|
||||
/* Register, common to both PC87310 and ALi M5105. */
|
||||
pc87310_log("SIO: Common register written %02X\n", val);
|
||||
|
||||
/* Reconfigure parallel port. */
|
||||
if (valxor & 0x03)
|
||||
/* Bits 1, 0: 1, 1 = Disable parallel port. */
|
||||
lpt1_handler(dev);
|
||||
|
||||
/* Reconfigure serial ports. */
|
||||
if (valxor & 0x1c)
|
||||
serial_handler(dev);
|
||||
|
||||
/* Reconfigure IDE controller. */
|
||||
if ((dev->flags & FLAG_IDE) && (valxor & 0x20)) {
|
||||
pc87310_log("SIO: HDC disabled\n");
|
||||
ide_pri_disable();
|
||||
/* Bit 5: 1 = Disable IDE controller. */
|
||||
if (!(val & 0x20)) {
|
||||
pc87310_log("SIO: HDC enabled\n");
|
||||
ide_set_base(0, 0x1f0);
|
||||
ide_set_side(0, 0x3f6);
|
||||
ide_pri_enable();
|
||||
}
|
||||
}
|
||||
|
||||
/* Reconfigure floppy disk controller. */
|
||||
if (valxor & 0x40) {
|
||||
pc87310_log("SIO: FDC disabled\n");
|
||||
fdc_remove(dev->fdc);
|
||||
/* Bit 6: 1 = Disable FDC. */
|
||||
if (!(val & 0x40)) {
|
||||
pc87310_log("SIO: FDC enabled\n");
|
||||
fdc_set_base(dev->fdc, FDC_PRIMARY_ADDR);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* ALi M5105 extension register. */
|
||||
pc87310_log("SIO: M5105 extension register written %02X\n", val);
|
||||
|
||||
/* Reconfigure serial ports. */
|
||||
if (valxor & 0x03)
|
||||
serial_handler(dev);
|
||||
}
|
||||
} else
|
||||
/* First write to config register. */
|
||||
dev->tries++;
|
||||
return;
|
||||
}
|
||||
|
||||
pc87310_log("SIO: written %01X\n", val);
|
||||
|
||||
/* reconfigure parallel port */
|
||||
if (valxor & 0x03) {
|
||||
lpt1_remove();
|
||||
/* bits 0-1: 11 disable parallel port */
|
||||
if (!((val & 1) && (val & 2)))
|
||||
lpt1_handler(dev);
|
||||
}
|
||||
/* reconfigure serial ports */
|
||||
if (valxor & 0x1c) {
|
||||
serial_remove(dev->uart[0]);
|
||||
serial_remove(dev->uart[1]);
|
||||
/* bit 2: 1 disable first serial port */
|
||||
if (!(val & 4))
|
||||
serial_handler(dev, 0);
|
||||
/* bit 3: 1 disable second serial port */
|
||||
if (!(val & 8))
|
||||
serial_handler(dev, 1);
|
||||
}
|
||||
/* reconfigure IDE controller */
|
||||
if (valxor & 0x20) {
|
||||
pc87310_log("SIO: HDC disabled\n");
|
||||
ide_pri_disable();
|
||||
/* bit 5: 1 disable ide controller */
|
||||
if (!(val & 0x20) && HAS_IDE_FUNCTIONALITY) {
|
||||
pc87310_log("SIO: HDC enabled\n");
|
||||
ide_set_base(0, 0x1f0);
|
||||
ide_set_side(0, 0x3f6);
|
||||
ide_pri_enable();
|
||||
}
|
||||
}
|
||||
/* reconfigure floppy disk controller */
|
||||
if (valxor & 0x40) {
|
||||
pc87310_log("SIO: FDC disabled\n");
|
||||
fdc_remove(dev->fdc);
|
||||
/* bit 6: 1 disable fdc */
|
||||
if (!(val & 0x40)) {
|
||||
pc87310_log("SIO: FDC enabled\n");
|
||||
fdc_set_base(dev->fdc, FDC_PRIMARY_ADDR);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
@@ -198,12 +237,13 @@ pc87310_read(UNUSED(uint16_t port), void *priv)
|
||||
{
|
||||
pc87310_t *dev = (pc87310_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
uint8_t idx = (uint8_t) ((port & 0x0002) >> 1);
|
||||
|
||||
dev->tries = 0;
|
||||
|
||||
ret = dev->reg;
|
||||
ret = dev->regs[idx];
|
||||
|
||||
pc87310_log("SIO: read %01X\n", ret);
|
||||
pc87310_log("[%04X:%08X] [R] %02X = %02X\n", CS, cpu_state.pc, port, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -211,22 +251,18 @@ pc87310_read(UNUSED(uint16_t port), void *priv)
|
||||
void
|
||||
pc87310_reset(pc87310_t *dev)
|
||||
{
|
||||
dev->reg = 0x0;
|
||||
dev->tries = 0;
|
||||
/*
|
||||
0 = 360 rpm @ 500 kbps for 3.5"
|
||||
1 = Default, 300 rpm @ 500, 300, 250, 1000 kbps for 3.5"
|
||||
*/
|
||||
lpt1_remove();
|
||||
dev->regs[0] = 0x00;
|
||||
dev->regs[1] = 0x00;
|
||||
|
||||
dev->tries = 0;
|
||||
|
||||
lpt1_handler(dev);
|
||||
serial_remove(dev->uart[0]);
|
||||
serial_remove(dev->uart[1]);
|
||||
serial_handler(dev, 0);
|
||||
serial_handler(dev, 1);
|
||||
serial_handler(dev);
|
||||
if (dev->flags & FLAG_IDE) {
|
||||
ide_pri_disable();
|
||||
ide_pri_enable();
|
||||
}
|
||||
fdc_reset(dev->fdc);
|
||||
#if 0
|
||||
ide_pri_enable();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -240,25 +276,28 @@ pc87310_close(void *priv)
|
||||
static void *
|
||||
pc87310_init(const device_t *info)
|
||||
{
|
||||
pc87310_t *dev = (pc87310_t *) malloc(sizeof(pc87310_t));
|
||||
memset(dev, 0, sizeof(pc87310_t));
|
||||
pc87310_t *dev = (pc87310_t *) calloc(1, sizeof(pc87310_t));
|
||||
|
||||
/* Avoid conflicting with machines that make no use of the PC87310 Internal IDE */
|
||||
HAS_IDE_FUNCTIONALITY = info->local;
|
||||
dev->flags = info->local;
|
||||
|
||||
dev->fdc = device_add(&fdc_at_nsc_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);
|
||||
|
||||
if (HAS_IDE_FUNCTIONALITY)
|
||||
device_add(&ide_isa_device);
|
||||
if (dev->flags & FLAG_IDE)
|
||||
device_add((dev->flags & FLAG_ALI) ? &ide_vlb_device : &ide_isa_device);
|
||||
|
||||
pc87310_reset(dev);
|
||||
|
||||
io_sethandler(0x3f3, 0x0001,
|
||||
pc87310_read, NULL, NULL, pc87310_write, NULL, NULL, dev);
|
||||
|
||||
if (dev->flags & FLAG_ALI)
|
||||
io_sethandler(0x3f1, 0x0001,
|
||||
pc87310_read, NULL, NULL, pc87310_write, NULL, NULL, dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
@@ -280,7 +319,21 @@ const device_t pc87310_ide_device = {
|
||||
.name = "National Semiconductor PC87310 Super I/O with IDE functionality",
|
||||
.internal_name = "pc87310_ide",
|
||||
.flags = 0,
|
||||
.local = 1,
|
||||
.local = FLAG_IDE,
|
||||
.init = pc87310_init,
|
||||
.close = pc87310_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t ali5105_device = {
|
||||
.name = "ALi M5105 Super I/O",
|
||||
.internal_name = "ali5105",
|
||||
.flags = 0,
|
||||
.local = FLAG_ALI,
|
||||
.init = pc87310_init,
|
||||
.close = pc87310_close,
|
||||
.reset = NULL,
|
||||
|
||||
@@ -122,7 +122,7 @@ pc87311_write(uint16_t addr, uint8_t val, void *priv)
|
||||
static uint8_t
|
||||
pc87311_read(UNUSED(uint16_t addr), void *priv)
|
||||
{
|
||||
pc87311_t *dev = (pc87311_t *) priv;
|
||||
const pc87311_t *dev = (pc87311_t *) priv;
|
||||
|
||||
return dev->regs[dev->index];
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ prime3b_write(uint16_t addr, uint8_t val, void *priv)
|
||||
static uint8_t
|
||||
prime3b_read(UNUSED(uint16_t addr), void *priv)
|
||||
{
|
||||
prime3b_t *dev = (prime3b_t *) priv;
|
||||
const prime3b_t *dev = (prime3b_t *) priv;
|
||||
|
||||
return dev->regs[dev->index];
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ prime3c_write(uint16_t addr, uint8_t val, void *priv)
|
||||
static uint8_t
|
||||
prime3c_read(UNUSED(uint16_t addr), void *priv)
|
||||
{
|
||||
prime3c_t *dev = (prime3c_t *) priv;
|
||||
const prime3c_t *dev = (prime3c_t *) priv;
|
||||
|
||||
return dev->regs[dev->index];
|
||||
}
|
||||
|
||||
@@ -18,6 +18,35 @@
|
||||
* Copyright 2016-2021 Miran Grca.
|
||||
* Copyright 2021 RichardG.
|
||||
*/
|
||||
|
||||
/*
|
||||
UMC UM8669F non-PnP register definitions
|
||||
|
||||
C0:
|
||||
[7] Infrared half duplex
|
||||
[4:3] LPT mode:
|
||||
00 SPP
|
||||
01 EPP
|
||||
10 ECP
|
||||
11 ECP + EPP
|
||||
|
||||
C1:
|
||||
[7] Enable PnP access
|
||||
[6:0] Always set regardless of PnP access enabled/disabled
|
||||
|
||||
C2:
|
||||
[6:5] Potentially pin muxing mode: (names from AMI "IR group" setup option)
|
||||
00 Reserved
|
||||
01 A (no IDE)
|
||||
10 B (no IDE)
|
||||
11 C
|
||||
[4:3] Infrared mode:
|
||||
00 Reserved
|
||||
01 HPSIR
|
||||
10 ASKIR
|
||||
11 Disabled
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
@@ -35,11 +64,15 @@
|
||||
#include <86box/fdd.h>
|
||||
#include <86box/fdc.h>
|
||||
#include <86box/gameport.h>
|
||||
#include <86box/sio.h>
|
||||
#include <86box/hdc.h>
|
||||
#include <86box/isapnp.h>
|
||||
#include <86box/hdc_ide.h>
|
||||
#include <86box/sio.h>
|
||||
#include <86box/plat_unused.h>
|
||||
|
||||
/* This ROM was reconstructed out of many assumptions, some of which based on the IT8671F. */
|
||||
/* Real chips don't have a PnP ROM and instead rely on the BIOS going in blind.
|
||||
We create a fake ROM here (with values based on the IT8671F) to delegate
|
||||
all the logical device register handling over to the ISAPnP subsystem. */
|
||||
static uint8_t um8669f_pnp_rom[] = {
|
||||
0x55, 0xa3, 0x86, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, /* UMC8669, dummy checksum (filled in by isapnp_add_card) */
|
||||
0x0a, 0x10, 0x10, /* PnP version 1.0, vendor version 1.0 */
|
||||
@@ -61,7 +94,9 @@ static uint8_t um8669f_pnp_rom[] = {
|
||||
0x22, 0xfa, 0x1f, /* IRQ 1/3/4/5/6/7/8/9/10/11/12 */
|
||||
0x47, 0x00, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 10-bit, 8-byte alignment, 8 addresses */
|
||||
|
||||
0x15, 0x41, 0xd0, 0xff, 0xff, 0x00, /* logical device PNPFFFF (just a dummy to create a gap in LDNs) */
|
||||
0x15, 0x41, 0xd0, 0x06, 0x00, 0x01, /* logical device PNP0600, can participate in boot */
|
||||
0x22, 0xfa, 0x1f, /* IRQ 1/3/4/5/6/7/8/9/10/11/12 */
|
||||
0x47, 0x00, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 10-bit, 8-byte alignment, 8 addresses */
|
||||
|
||||
0x15, 0x41, 0xd0, 0xb0, 0x2f, 0x01, /* logical device PNPB02F, can participate in boot */
|
||||
0x47, 0x00, 0x00, 0x01, 0xf8, 0x03, 0x08, 0x08, /* I/O 0x100-0x3F8, decodes 10-bit, 8-byte alignment, 8 addresses */
|
||||
@@ -87,7 +122,9 @@ static const isapnp_device_config_t um8669f_pnp_defaults[] = {
|
||||
.io = { { .base = LPT1_ADDR }, },
|
||||
.irq = { { .irq = LPT1_IRQ }, }
|
||||
}, {
|
||||
.activate = 0
|
||||
.activate = 0,
|
||||
.io = { { .base = 0x1f0 }, },
|
||||
.irq = { { .irq = 14 }, }
|
||||
}, {
|
||||
.activate = 0,
|
||||
.io = { { .base = 0x200 }, }
|
||||
@@ -113,15 +150,14 @@ um8669f_log(const char *fmt, ...)
|
||||
#endif
|
||||
|
||||
typedef struct um8669f_t {
|
||||
int locked;
|
||||
int cur_reg_108;
|
||||
void *pnp_card;
|
||||
isapnp_device_config_t *pnp_config[5];
|
||||
|
||||
uint8_t regs_108[256];
|
||||
uint8_t locked;
|
||||
uint8_t cur_reg;
|
||||
void *pnp_card;
|
||||
uint8_t regs[3];
|
||||
|
||||
fdc_t *fdc;
|
||||
serial_t *uart[2];
|
||||
uint8_t ide;
|
||||
void *gameport;
|
||||
} um8669f_t;
|
||||
|
||||
@@ -178,6 +214,22 @@ um8669f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pri
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED))
|
||||
um8669f_log("UM8669F: IDE enabled at port %04X IRQ %d\n", config->io[0].base, config->irq[0].irq);
|
||||
else
|
||||
um8669f_log("UM8669F: IDE disabled\n");
|
||||
|
||||
if (dev->ide < IDE_BUS_MAX) {
|
||||
config->io[1].base = config->io[0].base + 0x206; /* status port apparently fixed */
|
||||
#if (defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64)
|
||||
ide_pnp_config_changed(0, config, (void *) (int64_t) dev->ide);
|
||||
#else
|
||||
ide_pnp_config_changed(0, config, (void *) (int) dev->ide);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) {
|
||||
um8669f_log("UM8669F: Game port enabled at port %04X\n", config->io[0].base);
|
||||
@@ -186,6 +238,7 @@ um8669f_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pri
|
||||
um8669f_log("UM8669F: Game port disabled\n");
|
||||
gameport_remap(dev->gameport, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
@@ -207,11 +260,11 @@ um8669f_write(uint16_t port, uint8_t val, void *priv)
|
||||
if (val == 0x55)
|
||||
dev->locked = 1;
|
||||
else
|
||||
dev->cur_reg_108 = val;
|
||||
} else {
|
||||
dev->regs_108[dev->cur_reg_108] = val;
|
||||
dev->cur_reg = val;
|
||||
} else if ((dev->cur_reg >= 0xc0) && (dev->cur_reg <= 0xc2)) {
|
||||
dev->regs[dev->cur_reg & 3] = val;
|
||||
|
||||
if (dev->cur_reg_108 == 0xc1) {
|
||||
if (dev->cur_reg == 0xc1) {
|
||||
um8669f_log("UM8669F: ISAPnP %sabled\n", (val & 0x80) ? "en" : "dis");
|
||||
isapnp_enable_card(dev->pnp_card, (val & 0x80) ? ISAPNP_CARD_FORCE_CONFIG : ISAPNP_CARD_DISABLE);
|
||||
}
|
||||
@@ -222,14 +275,14 @@ um8669f_write(uint16_t port, uint8_t val, void *priv)
|
||||
uint8_t
|
||||
um8669f_read(uint16_t port, void *priv)
|
||||
{
|
||||
um8669f_t *dev = (um8669f_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
const um8669f_t *dev = (um8669f_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
if (!dev->locked) {
|
||||
if (port == 0x108)
|
||||
ret = dev->cur_reg_108; /* ??? */
|
||||
else
|
||||
ret = dev->regs_108[dev->cur_reg_108];
|
||||
ret = dev->cur_reg; /* ??? */
|
||||
else if ((dev->cur_reg >= 0xc0) && (dev->cur_reg <= 0xc2))
|
||||
ret = dev->regs[dev->cur_reg & 3];
|
||||
}
|
||||
|
||||
um8669f_log("UM8669F: read(%04X) = %02X\n", port, ret);
|
||||
@@ -250,6 +303,9 @@ um8669f_reset(um8669f_t *dev)
|
||||
|
||||
lpt1_remove();
|
||||
|
||||
if (dev->ide < IDE_BUS_MAX)
|
||||
ide_remove_handlers(dev->ide);
|
||||
|
||||
isapnp_enable_card(dev->pnp_card, ISAPNP_CARD_DISABLE);
|
||||
|
||||
dev->locked = 1;
|
||||
@@ -268,9 +324,9 @@ um8669f_close(void *priv)
|
||||
}
|
||||
|
||||
static void *
|
||||
um8669f_init(UNUSED(const device_t *info))
|
||||
um8669f_init(const device_t *info)
|
||||
{
|
||||
um8669f_log("UM8669F: init()\n");
|
||||
um8669f_log("UM8669F: init(%02X)\n", info->local);
|
||||
|
||||
um8669f_t *dev = (um8669f_t *) malloc(sizeof(um8669f_t));
|
||||
memset(dev, 0, sizeof(um8669f_t));
|
||||
@@ -284,6 +340,10 @@ um8669f_init(UNUSED(const device_t *info))
|
||||
dev->uart[0] = device_add_inst(&ns16550_device, 1);
|
||||
dev->uart[1] = device_add_inst(&ns16550_device, 2);
|
||||
|
||||
dev->ide = info->local;
|
||||
if (dev->ide < IDE_BUS_MAX)
|
||||
device_add(&ide_isa_device);
|
||||
|
||||
dev->gameport = gameport_add(&gameport_sio_device);
|
||||
|
||||
io_sethandler(0x0108, 0x0002,
|
||||
@@ -298,6 +358,20 @@ const device_t um8669f_device = {
|
||||
.name = "UMC UM8669F Super I/O",
|
||||
.internal_name = "um8669f",
|
||||
.flags = 0,
|
||||
.local = 0xff,
|
||||
.init = um8669f_init,
|
||||
.close = um8669f_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t um8669f_ide_device = {
|
||||
.name = "UMC UM8669F Super I/O (With IDE)",
|
||||
.internal_name = "um8669f_ide",
|
||||
.flags = 0,
|
||||
.local = 0,
|
||||
.init = um8669f_init,
|
||||
.close = um8669f_close,
|
||||
@@ -307,3 +381,17 @@ const device_t um8669f_device = {
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t um8669f_ide_sec_device = {
|
||||
.name = "UMC UM8669F Super I/O (With Secondary IDE)",
|
||||
.internal_name = "um8669f_ide_sec",
|
||||
.flags = 0,
|
||||
.local = 1,
|
||||
.init = um8669f_init,
|
||||
.close = um8669f_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
@@ -374,6 +374,8 @@ w83787f_read(uint16_t port, void *priv)
|
||||
static void
|
||||
w83787f_reset(w83787f_t *dev)
|
||||
{
|
||||
uint16_t hefere = dev->reg_init & 0x0100;
|
||||
|
||||
lpt1_remove();
|
||||
lpt1_init(LPT1_ADDR);
|
||||
lpt1_irq(LPT1_IRQ);
|
||||
@@ -410,7 +412,7 @@ w83787f_reset(w83787f_t *dev)
|
||||
dev->regs[0x07] = 0xF5;
|
||||
dev->regs[0x09] = dev->reg_init & 0xff;
|
||||
dev->regs[0x0a] = 0x1F;
|
||||
dev->regs[0x0c] = 0x2C;
|
||||
dev->regs[0x0c] = 0x0C | (hefere >> 3);
|
||||
dev->regs[0x0d] = 0xA3;
|
||||
|
||||
gameport_remap(dev->gameport, 0);
|
||||
@@ -420,7 +422,7 @@ w83787f_reset(w83787f_t *dev)
|
||||
|
||||
w83787f_lpt_handler(dev);
|
||||
|
||||
dev->key = 0x89;
|
||||
dev->key = 0x88 | (hefere >> 8);
|
||||
|
||||
w83787f_remap(dev);
|
||||
|
||||
@@ -456,17 +458,31 @@ w83787f_init(const device_t *info)
|
||||
|
||||
dev->ide_start = !!(info->local & 0x40);
|
||||
|
||||
dev->reg_init = info->local & 0x0f;
|
||||
dev->reg_init = info->local & 0x010f;
|
||||
w83787f_reset(dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
const device_t w83787f_88h_device = {
|
||||
.name = "Winbond W83787F/IF Super I/O",
|
||||
.internal_name = "w83787f",
|
||||
.flags = 0,
|
||||
.local = 0x0009,
|
||||
.init = w83787f_init,
|
||||
.close = w83787f_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t w83787f_device = {
|
||||
.name = "Winbond W83787F/IF Super I/O",
|
||||
.internal_name = "w83787f",
|
||||
.flags = 0,
|
||||
.local = 0x09,
|
||||
.local = 0x0109,
|
||||
.init = w83787f_init,
|
||||
.close = w83787f_close,
|
||||
.reset = NULL,
|
||||
@@ -480,7 +496,7 @@ const device_t w83787f_ide_device = {
|
||||
.name = "Winbond W83787F/IF Super I/O (With IDE)",
|
||||
.internal_name = "w83787f_ide",
|
||||
.flags = 0,
|
||||
.local = 0x19,
|
||||
.local = 0x0119,
|
||||
.init = w83787f_init,
|
||||
.close = w83787f_close,
|
||||
.reset = NULL,
|
||||
@@ -494,7 +510,7 @@ const device_t w83787f_ide_en_device = {
|
||||
.name = "Winbond W83787F/IF Super I/O (With IDE Enabled)",
|
||||
.internal_name = "w83787f_ide_en",
|
||||
.flags = 0,
|
||||
.local = 0x59,
|
||||
.local = 0x0159,
|
||||
.init = w83787f_init,
|
||||
.close = w83787f_close,
|
||||
.reset = NULL,
|
||||
@@ -508,7 +524,7 @@ const device_t w83787f_ide_sec_device = {
|
||||
.name = "Winbond W83787F/IF Super I/O (With Secondary IDE)",
|
||||
.internal_name = "w83787f_ide_sec",
|
||||
.flags = 0,
|
||||
.local = 0x39,
|
||||
.local = 0x0139,
|
||||
.init = w83787f_init,
|
||||
.close = w83787f_close,
|
||||
.reset = NULL,
|
||||
|
||||
Reference in New Issue
Block a user