86Box/src/port_92.c
2022-02-02 16:31:22 -05:00

261 lines
5 KiB
C

/*
* 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 Port 92 used by PS/2 machines and 386+
* clones.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2019 Miran Grca.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/keyboard.h>
#include <86box/mem.h>
#include <86box/pit.h>
#include <86box/port_92.h>
#define PORT_92_INV 1
#define PORT_92_WORD 2
#define PORT_92_PCI 4
#define PORT_92_RESET 8
#define PORT_92_A20 16
static uint8_t
port_92_readb(uint16_t port, void *priv)
{
uint8_t ret = 0x00;
port_92_t *dev = (port_92_t *) priv;
if (port == 0x92) {
/* Return bit 1 directly from mem_a20_alt, so the
pin can be reset independently of the device. */
ret = (dev->reg & ~0x03) | (mem_a20_alt & 2) |
(cpu_alt_reset & 1);
if (dev->flags & PORT_92_INV)
ret |= 0xfc;
else if (dev->flags & PORT_92_PCI)
ret |= 0x24; /* Intel SIO datasheet says bits 2 and 5 are always 1. */
} else if (dev->flags & PORT_92_INV)
ret = 0xff;
return ret;
}
static uint16_t
port_92_readw(uint16_t port, void *priv)
{
uint16_t ret = 0xffff;
port_92_t *dev = (port_92_t *) priv;
if (!(dev->flags & PORT_92_PCI))
ret = port_92_readb(port, priv);
return ret;
}
static void
port_92_pulse(void *priv)
{
resetx86();
cpu_set_edx();
}
static void
port_92_writeb(uint16_t port, uint8_t val, void *priv)
{
port_92_t *dev = (port_92_t *) priv;
if (port != 0x92)
return;
dev->reg = val & 0x03;
if ((mem_a20_alt ^ val) & 2) {
mem_a20_alt = (val & 2);
mem_a20_recalc();
}
if ((~cpu_alt_reset & val) & 1)
timer_set_delay_u64(&dev->pulse_timer, dev->pulse_period);
else if (!(val & 1))
timer_disable(&dev->pulse_timer);
cpu_alt_reset = (val & 1);
if (dev->flags & PORT_92_INV)
dev->reg |= 0xfc;
}
static void
port_92_writew(uint16_t port, uint16_t val, void *priv)
{
port_92_t *dev = (port_92_t *) priv;
if (!(dev->flags & PORT_92_PCI))
port_92_writeb(port, val & 0xff, priv);
}
void
port_92_set_period(void *priv, uint64_t pulse_period)
{
port_92_t *dev = (port_92_t *) priv;
dev->pulse_period = pulse_period;
}
void
port_92_set_features(void *priv, int reset, int a20)
{
port_92_t *dev = (port_92_t *) priv;
dev->flags &= ~(PORT_92_RESET | PORT_92_A20);
if (reset)
dev->flags |= PORT_92_RESET;
timer_disable(&dev->pulse_timer);
if (a20) {
dev->flags |= PORT_92_A20;
mem_a20_alt = (dev->reg & 2);
} else
mem_a20_alt = 0;
mem_a20_recalc();
}
void
port_92_add(void *priv)
{
port_92_t *dev = (port_92_t *) priv;
if (dev->flags & (PORT_92_WORD | PORT_92_PCI))
io_sethandler(0x0092, 2,
port_92_readb, port_92_readw, NULL, port_92_writeb, port_92_writew, NULL, dev);
else
io_sethandler(0x0092, 1,
port_92_readb, NULL, NULL, port_92_writeb, NULL, NULL, dev);
}
void
port_92_remove(void *priv)
{
port_92_t *dev = (port_92_t *) priv;
if (dev->flags & (PORT_92_WORD | PORT_92_PCI))
io_removehandler(0x0092, 2,
port_92_readb, port_92_readw, NULL, port_92_writeb, port_92_writew, NULL, dev);
else
io_removehandler(0x0092, 1,
port_92_readb, NULL, NULL, port_92_writeb, NULL, NULL, dev);
}
static void
port_92_close(void *priv)
{
port_92_t *dev = (port_92_t *) priv;
timer_disable(&dev->pulse_timer);
free(dev);
}
void *
port_92_init(const device_t *info)
{
port_92_t *dev = (port_92_t *) malloc(sizeof(port_92_t));
memset(dev, 0, sizeof(port_92_t));
dev->flags = info->local & 0xff;
timer_add(&dev->pulse_timer, port_92_pulse, dev, 0);
dev->reg = 0;
mem_a20_alt = 0;
mem_a20_recalc();
cpu_alt_reset = 0;
flushmmucache();
port_92_add(dev);
dev->pulse_period = (uint64_t) (4.0 * SYSCLK * (double)(1ULL << 32ULL));
dev->flags |= (PORT_92_RESET | PORT_92_A20);
return dev;
}
const device_t port_92_device = {
"Port 92 Register",
"port_92",
0,
0,
port_92_init, port_92_close, NULL,
{ NULL }, NULL, NULL,
NULL
};
const device_t port_92_inv_device = {
"Port 92 Register (inverted bits 2-7)",
"port_92_inv",
0,
PORT_92_INV,
port_92_init, port_92_close, NULL,
{ NULL }, NULL, NULL,
NULL
};
const device_t port_92_word_device = {
"Port 92 Register (16-bit)",
"port_92_word",
0,
PORT_92_WORD,
port_92_init, port_92_close, NULL,
{ NULL }, NULL, NULL,
NULL
};
const device_t port_92_pci_device = {
"Port 92 Register (PCI)",
"port_92_pci",
0,
PORT_92_PCI,
port_92_init, port_92_close, NULL,
{ NULL }, NULL, NULL,
NULL
};