All the required fixes - the Dell OptiPlex Gn+ now works correctly.

This commit is contained in:
OBattler
2025-05-21 20:49:54 +02:00
parent 4e3c01c41a
commit 455622492b
19 changed files with 1310 additions and 672 deletions

View File

@@ -36,6 +36,7 @@
#include <86box/pit.h>
#include <86box/apm.h>
#include <86box/acpi.h>
#include <86box/dma.h>
#include <86box/machine.h>
#include <86box/i2c.h>
#include <86box/video.h>
@@ -1025,8 +1026,13 @@ acpi_reg_write_common_regs(UNUSED(int size), uint16_t addr, uint8_t val, void *p
nvr_reg_write(0x000f, 0xff, dev->nvr);
}
if (sus_typ & SUS_RESET_PCI)
if (sus_typ & SUS_RESET_PCI) {
/* DMA is part of the southbridge so it responds to PCI reset. */
dma_reset();
dma_set_at(1);
device_reset_all(DEVICE_PCI);
}
if (sus_typ & SUS_RESET_CPU)
cpu_alt_reset = 0;

View File

@@ -155,6 +155,7 @@ piix_ide_handlers(piix_t *dev, int bus)
uint16_t side;
if (bus & 0x01) {
piix_log("Disabling primary IDE...\n");
ide_pri_disable();
if (dev->type == 5) {
@@ -170,11 +171,14 @@ piix_ide_handlers(piix_t *dev, int bus)
ide_set_side(0, side);
}
if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x41] & 0x80))
if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x41] & 0x80)) {
piix_log("Enabling primary IDE...\n");
ide_pri_enable();
}
}
if (bus & 0x02) {
piix_log("Disabling secondary IDE...\n");
ide_sec_disable();
if (dev->type == 5) {
@@ -190,8 +194,10 @@ piix_ide_handlers(piix_t *dev, int bus)
ide_set_side(1, side);
}
if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x43] & 0x80))
if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x43] & 0x80)) {
piix_log("Enabling secondary IDE...\n");
ide_sec_enable();
}
}
}
@@ -465,6 +471,13 @@ piix_write(int func, int addr, uint8_t val, void *priv)
uint8_t *fregs;
uint16_t base;
/* Dell OptiPlex Gn+ shows that register 02:FF is aliased in 01:FF. */
if ((dev->type == 4) && (func == 1) && (addr == 0xff))
func = 2;
if ((func == 1) || (addr == 0xf8) || (addr == 0xf9))
piix_log("[W] %02X:%02X = %02X\n", func, addr, val);
/* Return on unsupported function. */
if (dev->max_func > 0) {
if (func > dev->max_func)
@@ -736,6 +749,8 @@ piix_write(int func, int addr, uint8_t val, void *priv)
fregs[addr] = val;
break;
case 0xb0:
if (val & 0x10)
warning("Write %02X to B0\n", val);
if (dev->type == 4)
fregs[addr] = (fregs[addr] & 0x8c) | (val & 0x73);
else if (dev->type == 5)
@@ -745,6 +760,8 @@ piix_write(int func, int addr, uint8_t val, void *priv)
alt_access = !!(val & 0x20);
break;
case 0xb1:
if (val & 0x18)
warning("Write %02X to B1\n", val);
if (dev->type > 3)
fregs[addr] = val & 0xdf;
break;
@@ -923,6 +940,12 @@ piix_write(int func, int addr, uint8_t val, void *priv)
if (dev->type > 4)
fregs[addr] = val;
break;
case 0xf8:
case 0xf9:
/* Undocumented! */
if (dev->type == 4)
fregs[addr] = val;
break;
default:
break;
}
@@ -1169,6 +1192,10 @@ piix_read(int func, int addr, void *priv)
uint8_t ret = 0xff;
const uint8_t *fregs;
/* Dell OptiPlex Gn+ shows that register 02:FF is aliased in 01:FF. */
if ((dev->type == 4) && (func == 1) && (addr == 0xff))
func = 2;
if ((dev->type == 3) && (func == 2) && (dev->max_func == 1) && (addr >= 0x40))
ret = 0x00;
@@ -1199,7 +1226,7 @@ piix_reset_hard(piix_t *dev)
sff_set_slot(dev->bm[1], dev->pci_slot);
sff_set_irq_pin(dev->bm[1], PCI_INTA);
sff_set_irq_line(dev->bm[1], 14);
sff_set_irq_line(dev->bm[1], 15);
sff_set_irq_mode(dev->bm[1], IRQ_MODE_LEGACY);
}
@@ -1315,6 +1342,10 @@ piix_reset_hard(piix_t *dev)
fregs[0x45] = 0x55;
fregs[0x46] = 0x01;
}
if (dev->type == 4) {
fregs[0xf8] = 0x30;
fregs[0xf9] = 0x0f;
}
if ((dev->type == 1) && (dev->rev == 2))
dev->max_func = 0; /* It starts with IDE disabled, then enables it. */
else
@@ -1678,7 +1709,7 @@ const device_t piix4_device = {
.name = "Intel 82371AB/EB (PIIX4/PIIX4E)",
.internal_name = "piix4",
.flags = DEVICE_PCI,
.local = 0x71100004,
.local = 0x71100014,
.init = piix_init,
.close = piix_close,
.reset = piix_reset,

View File

@@ -145,6 +145,11 @@ typedef struct atkbc_t {
/* Internal FIFO for the purpose of commands with multi-byte output. */
uint8_t key_ctrl_queue[64];
uint8_t handler_enable[2];
uint16_t base_addr[2];
uint16_t irq[2];
uint32_t flags;
/* Main timers. */
@@ -157,8 +162,13 @@ typedef struct atkbc_t {
/* Local copies of the pointers to both ports for easier swapping (AMI '5' MegaKey). */
kbc_at_port_t *ports[2];
uint8_t (*write60_ven)(void *priv, uint8_t val);
uint8_t (*write64_ven)(void *priv, uint8_t val);
struct {
uint8_t (*read)(uint16_t port, void *priv);
void (*write)(uint16_t port, uint8_t val, void *priv);
} handlers[2];
uint8_t (*write_cmd_data_ven)(void *priv, uint8_t val);
uint8_t (*write_cmd_ven)(void *priv, uint8_t val);
} atkbc_t;
/* Keyboard controller ports. */
@@ -167,8 +177,6 @@ kbc_at_port_t *kbc_at_ports[2] = { NULL, NULL };
static uint8_t kbc_ami_revision = '8';
static uint8_t kbc_award_revision = 0x42;
static uint8_t kbc_handler_set = 0;
static void (*kbc_at_do_poll)(atkbc_t *dev);
/* Non-translated to translated scan codes. */
@@ -362,12 +370,19 @@ kbc_do_irq(atkbc_t *dev)
if (dev->do_irq) {
/* WARNING: On PS/2, all IRQ's are level-triggered, but the IBM PS/2 KBC firmware is explicitly
written to pulse its P2 IRQ bits, so they should be kept as as edge-triggered here. */
picint_common(1 << 1, 0, 0, NULL);
picint_common(1 << 12, 0, 0, NULL);
if (dev->channel >= 2)
picint_common(1 << 12, 0, 1, NULL);
else
picint_common(1 << 1, 0, 1, NULL);
if (dev->irq[0] != 0xffff)
picint_common(1 << dev->irq[0], 0, 0, NULL);
if (dev->irq[1] != 0xffff)
picint_common(1 << dev->irq[1], 0, 0, NULL);
if (dev->channel >= 2) {
if (dev->irq[1] != 0xffff)
picint_common(1 << dev->irq[1], 0, 1, NULL);
} else {
if (dev->irq[0] != 0xffff)
picint_common(1 << dev->irq[0], 0, 1, NULL);
}
dev->do_irq = 0;
}
@@ -404,7 +419,9 @@ kbc_send_to_ob(atkbc_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi)
} else if (dev->mem[0x20] & 0x01)
kbc_set_do_irq(dev, channel);
} else if (dev->mem[0x20] & 0x01)
picintlevel(1 << 1, &dev->irq_state); /* AT KBC: IRQ 1 is level-triggered because it is tied to OBF. */
/* AT KBC: IRQ 1 is level-triggered because it is tied to OBF. */
if (dev->irq[0] != 0xffff)
picintlevel(1 << dev->irq[0], &dev->irq_state);
#ifdef WRONG_CONDITION
if ((dev->channel > 0) || dev->is_asic || (kbc_ven == KBC_VEN_IBM_PS1) || (kbc_ven == KBC_VEN_IBM))
@@ -784,10 +801,12 @@ write_p2(atkbc_t *dev, uint8_t val)
/* PS/2: Handle IRQ's. */
if (dev->misc_flags & FLAG_PS2) {
/* IRQ 12 */
picint_common(1 << 12, 0, val & 0x20, NULL);
if (dev->irq[1] != 0xffff)
picint_common(1 << dev->irq[1], 0, val & 0x20, NULL);
/* IRQ 1 */
picint_common(1 << 1, 0, val & 0x10, NULL);
if (dev->irq[0] != 0xffff)
picint_common(1 << dev->irq[0], 0, val & 0x10, NULL);
}
#endif
@@ -932,7 +951,7 @@ pulse_poll(void *priv)
}
static uint8_t
write64_generic(void *priv, uint8_t val)
write_cmd_generic(void *priv, uint8_t val)
{
atkbc_t *dev = (atkbc_t *) priv;
uint8_t current_drive;
@@ -1161,7 +1180,7 @@ write64_generic(void *priv, uint8_t val)
}
static uint8_t
write60_ami(void *priv, uint8_t val)
write_cmd_data_ami(void *priv, uint8_t val)
{
atkbc_t *dev = (atkbc_t *) priv;
@@ -1231,7 +1250,7 @@ kbc_at_set_ps2(void *priv, const uint8_t ps2)
}
static uint8_t
write64_ami(void *priv, uint8_t val)
write_cmd_ami(void *priv, uint8_t val)
{
atkbc_t *dev = (atkbc_t *) priv;
uint8_t kbc_ven = dev->flags & KBC_VEN_MASK;
@@ -1436,11 +1455,11 @@ write64_ami(void *priv, uint8_t val)
break;
}
return write64_generic(dev, val);
return write_cmd_generic(dev, val);
}
static uint8_t
write60_phoenix(void *priv, uint8_t val)
write_cmd_data_phoenix(void *priv, uint8_t val)
{
atkbc_t *dev = (atkbc_t *) priv;
@@ -1513,7 +1532,7 @@ write60_phoenix(void *priv, uint8_t val)
}
static uint8_t
write64_phoenix(void *priv, uint8_t val)
write_cmd_phoenix(void *priv, uint8_t val)
{
atkbc_t *dev = (atkbc_t *) priv;
@@ -1659,11 +1678,11 @@ write64_phoenix(void *priv, uint8_t val)
break;
}
return write64_generic(dev, val);
return write_cmd_generic(dev, val);
}
static uint8_t
write64_siemens(void *priv, uint8_t val)
write_cmd_siemens(void *priv, uint8_t val)
{
atkbc_t *dev = (atkbc_t *) priv;
@@ -1692,11 +1711,11 @@ write64_siemens(void *priv, uint8_t val)
break;
}
return write64_ami(dev, val);
return write_cmd_ami(dev, val);
}
static uint8_t
write60_quadtel(void *priv, UNUSED(uint8_t val))
write_cmd_data_quadtel(void *priv, UNUSED(uint8_t val))
{
const atkbc_t *dev = (atkbc_t *) priv;
@@ -1713,7 +1732,7 @@ write60_quadtel(void *priv, UNUSED(uint8_t val))
}
static uint8_t
write64_olivetti(void *priv, uint8_t val)
write_cmd_olivetti(void *priv, uint8_t val)
{
atkbc_t *dev = (atkbc_t *) priv;
@@ -1734,11 +1753,11 @@ write64_olivetti(void *priv, uint8_t val)
break;
}
return write64_generic(dev, val);
return write_cmd_generic(dev, val);
}
static uint8_t
write64_quadtel(void *priv, uint8_t val)
write_cmd_quadtel(void *priv, uint8_t val)
{
atkbc_t *dev = (atkbc_t *) priv;
@@ -1757,11 +1776,11 @@ write64_quadtel(void *priv, uint8_t val)
break;
}
return write64_generic(dev, val);
return write_cmd_generic(dev, val);
}
static uint8_t
write60_toshiba(void *priv, uint8_t val)
write_cmd_data_toshiba(void *priv, uint8_t val)
{
const atkbc_t *dev = (atkbc_t *) priv;
@@ -1779,7 +1798,7 @@ write60_toshiba(void *priv, uint8_t val)
}
static uint8_t
write64_toshiba(void *priv, uint8_t val)
write_cmd_toshiba(void *priv, uint8_t val)
{
atkbc_t *dev = (atkbc_t *) priv;
@@ -1868,7 +1887,7 @@ write64_toshiba(void *priv, uint8_t val)
break;
}
return write64_generic(dev, val);
return write_cmd_generic(dev, val);
}
static void
@@ -1912,8 +1931,10 @@ kbc_at_process_cmd(void *priv)
/* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */
dev->p1 = dev->p1 & 0xff;
write_p2(dev, 0x4b);
picintc(0x1000);
picintc(0x0002);
if (dev->irq[1] != 0xffff)
picintc(1 << dev->irq[1]);
if (dev->irq[0] != 0xffff)
picintc(1 << dev->irq[0]);
}
dev->status = (dev->status & 0x0f) | 0x60;
@@ -1932,7 +1953,8 @@ kbc_at_process_cmd(void *priv)
/* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */
dev->p1 = dev->p1 & 0xff;
write_p2(dev, 0xcf);
picintclevel(0x0002, &dev->irq_state);
if (dev->irq[0] != 0xffff)
picintclevel(1 << dev->irq[0], &dev->irq_state);
dev->irq_state = 0;
}
@@ -2047,8 +2069,8 @@ kbc_at_process_cmd(void *priv)
* that. Otherwise, or if that handler fails,
* log a bad command.
*/
if (dev->write64_ven)
bad = dev->write64_ven(dev, dev->ib);
if (dev->write_cmd_ven)
bad = dev->write_cmd_ven(dev, dev->ib);
kbc_at_log(bad ? "ATkbc: bad controller command %02X\n" : "", dev->ib);
}
@@ -2134,8 +2156,8 @@ kbc_at_process_cmd(void *priv)
* it returns an error, log a bad
* controller command.
*/
if (dev->write60_ven)
bad = dev->write60_ven(dev, dev->ib);
if (dev->write_cmd_data_ven)
bad = dev->write_cmd_data_ven(dev, dev->ib);
if (bad) {
kbc_at_log("ATkbc: bad controller command %02x data %02x\n", dev->command, dev->ib);
@@ -2145,7 +2167,7 @@ kbc_at_process_cmd(void *priv)
}
static void
kbc_at_write(uint16_t port, uint8_t val, void *priv)
kbc_at_port_1_write(uint16_t port, uint8_t val, void *priv)
{
atkbc_t *dev = (atkbc_t *) priv;
uint8_t kbc_ven = dev->flags & KBC_VEN_MASK;
@@ -2153,83 +2175,89 @@ kbc_at_write(uint16_t port, uint8_t val, void *priv)
kbc_at_log("ATkbc: [%04X:%08X] write(%04X) = %02X\n", CS, cpu_state.pc, port, val);
switch (port) {
case 0x60:
dev->status &= ~STAT_CD;
if (fast_a20 && dev->wantdata && (dev->command == 0xd1)) {
kbc_at_log("ATkbc: write P2\n");
dev->status &= ~STAT_CD;
/* Fast A20 - ignore all other bits. */
write_p2_fast_a20(dev, (dev->p2 & 0xfd) | (val & 0x02));
if (fast_a20 && dev->wantdata && (dev->command == 0xd1)) {
kbc_at_log("ATkbc: write P2\n");
dev->wantdata = 0;
dev->state = STATE_MAIN_IBF;
/* Fast A20 - ignore all other bits. */
write_p2_fast_a20(dev, (dev->p2 & 0xfd) | (val & 0x02));
/*
Explicitly clear IBF so that any preceding
command is not executed.
*/
dev->status &= ~STAT_IFULL;
return;
}
break;
dev->wantdata = 0;
dev->state = STATE_MAIN_IBF;
case 0x64:
dev->status |= STAT_CD;
if (fast_a20 && (val == 0xd1)) {
kbc_at_log("ATkbc: write P2\n");
dev->wantdata = 1;
dev->state = STATE_KBC_PARAM;
dev->command = 0xd1;
/*
Explicitly clear IBF so that any preceding
command is not executed.
*/
dev->status &= ~STAT_IFULL;
return;
}
/*
Explicitly clear IBF so that any preceding
command is not executed.
*/
dev->status &= ~STAT_IFULL;
return;
} else if (fast_reset && ((val & 0xf0) == 0xf0)) {
pulse_output(dev, val & 0x0f);
dev->ib = val;
dev->status |= STAT_IFULL;
}
dev->state = STATE_MAIN_IBF;
static void
kbc_at_port_2_write(uint16_t port, uint8_t val, void *priv)
{
atkbc_t *dev = (atkbc_t *) priv;
uint8_t kbc_ven = dev->flags & KBC_VEN_MASK;
uint8_t fast_a20 = (kbc_ven != KBC_VEN_SIEMENS);
/*
Explicitly clear IBF so that any preceding
command is not executed.
*/
dev->status &= ~STAT_IFULL;
return;
} else if (val == 0xad) {
/* Fast track it because of the Bochs BIOS. */
kbc_at_log("ATkbc: disable keyboard\n");
set_enable_kbd(dev, 0);
kbc_at_log("ATkbc: [%04X:%08X] write(%04X) = %02X\n", CS, cpu_state.pc, port, val);
dev->state = STATE_MAIN_IBF;
dev->status |= STAT_CD;
/*
Explicitly clear IBF so that any preceding
command is not executed.
*/
dev->status &= ~STAT_IFULL;
return;
} else if (val == 0xae) {
/* Fast track it because of the LG MultiNet. */
kbc_at_log("ATkbc: enable keyboard\n");
set_enable_kbd(dev, 1);
if (fast_a20 && (val == 0xd1)) {
kbc_at_log("ATkbc: write P2\n");
dev->wantdata = 1;
dev->state = STATE_KBC_PARAM;
dev->command = 0xd1;
dev->state = STATE_MAIN_IBF;
/*
Explicitly clear IBF so that any preceding
command is not executed.
*/
dev->status &= ~STAT_IFULL;
return;
} else if (fast_reset && ((val & 0xf0) == 0xf0)) {
pulse_output(dev, val & 0x0f);
/*
Explicitly clear IBF so that any preceding
command is not executed.
*/
dev->status &= ~STAT_IFULL;
return;
}
break;
dev->state = STATE_MAIN_IBF;
default:
break;
/*
Explicitly clear IBF so that any preceding
command is not executed.
*/
dev->status &= ~STAT_IFULL;
return;
} else if (val == 0xad) {
/* Fast track it because of the Bochs BIOS. */
kbc_at_log("ATkbc: disable keyboard\n");
set_enable_kbd(dev, 0);
dev->state = STATE_MAIN_IBF;
/*
Explicitly clear IBF so that any preceding
command is not executed.
*/
dev->status &= ~STAT_IFULL;
return;
} else if (val == 0xae) {
/* Fast track it because of the LG MultiNet. */
kbc_at_log("ATkbc: enable keyboard\n");
set_enable_kbd(dev, 1);
dev->state = STATE_MAIN_IBF;
/*
Explicitly clear IBF so that any preceding
command is not executed.
*/
dev->status &= ~STAT_IFULL;
return;
}
dev->ib = val;
@@ -2237,7 +2265,7 @@ kbc_at_write(uint16_t port, uint8_t val, void *priv)
}
static uint8_t
kbc_at_read(uint16_t port, void *priv)
kbc_at_port_1_read(uint16_t port, void *priv)
{
atkbc_t *dev = (atkbc_t *) priv;
uint8_t ret = 0xff;
@@ -2245,26 +2273,32 @@ kbc_at_read(uint16_t port, void *priv)
if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)
cycles -= ISA_CYCLES(8);
switch (port) {
case 0x60:
ret = dev->ob;
dev->status &= ~STAT_OFULL;
/* TODO: IRQ is only tied to OBF on the AT KBC, on the PS/2 KBC, it is controlled by a P2 bit.
This also means that in AT mode, the IRQ is level-triggered. */
if (!(dev->misc_flags & FLAG_PS2))
picintclevel(1 << 1, &dev->irq_state);
if ((strstr(machine_get_internal_name(), "pb41") != NULL) && (cpu_override_dynarec == 1))
cpu_override_dynarec = 0;
break;
ret = dev->ob;
dev->status &= ~STAT_OFULL;
/*
TODO: IRQ is only tied to OBF on the AT KBC, on the PS/2 KBC, it is controlled by a P2 bit.
This also means that in AT mode, the IRQ is level-triggered.
*/
if (!(dev->misc_flags & FLAG_PS2) && (dev->irq[0] != 0xffff))
picintclevel(1 << dev->irq[0], &dev->irq_state);
if ((strstr(machine_get_internal_name(), "pb41") != NULL) && (cpu_override_dynarec == 1))
cpu_override_dynarec = 0;
case 0x64:
ret = dev->status;
break;
kbc_at_log("ATkbc: [%04X:%08X] read (%04X) = %02X\n", CS, cpu_state.pc, port, ret);
default:
kbc_at_log("ATkbc: read(%04x) invalid!\n",port);
break;
}
return ret;
}
static uint8_t
kbc_at_port_2_read(uint16_t port, void *priv)
{
atkbc_t *dev = (atkbc_t *) priv;
uint8_t ret = 0xff;
if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)
cycles -= ISA_CYCLES(8);
ret = dev->status;
kbc_at_log("ATkbc: [%04X:%08X] read (%04X) = %02X\n", CS, cpu_state.pc, port, ret);
@@ -2303,11 +2337,14 @@ kbc_at_reset(void *priv)
if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) {
dev->misc_flags |= FLAG_PS2;
kbc_at_do_poll = kbc_at_poll_ps2;
picintc(0x1000);
picintc(0x0002);
if (dev->irq[1] != 0xffff)
picintc(1 << dev->irq[1]);
if (dev->irq[0] != 0xffff)
picintc(1 << dev->irq[0]);
} else {
kbc_at_do_poll = kbc_at_poll_at;
picintclevel(0x0002, &dev->irq_state);
if (dev->irq[0] != 0xffff)
picintclevel(1 << dev->irq[0], &dev->irq_state);
dev->irq_state = 0;
}
@@ -2350,21 +2387,52 @@ kbc_at_close(void *priv)
}
void
kbc_at_handler(int set, void *priv)
kbc_at_port_handler(int num, int set, uint16_t port, void *priv)
{
if (kbc_handler_set) {
io_removehandler(0x0060, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, priv);
io_removehandler(0x0064, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, priv);
atkbc_t *dev = (atkbc_t *) priv;
if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000)) {
pclog("Disabling keyboard controller port %i at %04X...\n", num, dev->base_addr[num]);
io_removehandler(dev->base_addr[num], 1,
dev->handlers[num].read, NULL, NULL,
dev->handlers[num].write, NULL, NULL, priv);
}
kbc_handler_set = set;
dev->handler_enable[num] = set;
dev->base_addr[num] = port;
if (kbc_handler_set) {
io_sethandler(0x0060, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, priv);
io_sethandler(0x0064, 1, kbc_at_read, NULL, NULL, kbc_at_write, NULL, NULL, priv);
if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000)) {
pclog("Enabling keyboard controller port %i at %04X...\n", num, dev->base_addr[num]);
io_sethandler(dev->base_addr[num], 1,
dev->handlers[num].read, NULL, NULL,
dev->handlers[num].write, NULL, NULL, priv);
}
}
void
kbc_at_handler(int set, uint16_t port, void *priv)
{
kbc_at_port_handler(0, set, port, priv);
kbc_at_port_handler(1, set, port + 0x0004, priv);
}
void
kbc_at_set_irq(int num, uint16_t irq, void *priv)
{
atkbc_t *dev = (atkbc_t *) priv;
if (dev->irq[num] != 0xffff) {
if ((num == 0) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1))
picintclevel(1 << dev->irq[num], &dev->irq_state);
else
picintc(1 << dev->irq[num]);
}
dev->irq[num] = irq;
}
static void *
kbc_at_init(const device_t *info)
{
@@ -2383,16 +2451,21 @@ kbc_at_init(const device_t *info)
if (info->flags & DEVICE_PCI)
dev->misc_flags |= FLAG_PCI;
kbc_handler_set = 0;
kbc_at_handler(1, dev);
dev->handlers[0].read = kbc_at_port_1_read;
dev->handlers[0].write = kbc_at_port_1_write;
dev->handlers[1].read = kbc_at_port_2_read;
dev->handlers[1].write = kbc_at_port_2_write;
dev->irq[0] = 1;
dev->irq[1] = 12;
timer_add(&dev->kbc_poll_timer, kbc_at_poll, dev, 1);
timer_add(&dev->pulse_cb, pulse_poll, dev, 0);
timer_add(&dev->kbc_dev_poll_timer, kbc_at_dev_poll, dev, 1);
dev->write60_ven = NULL;
dev->write64_ven = NULL;
dev->write_cmd_data_ven = NULL;
dev->write_cmd_ven = NULL;
kbc_ami_revision = '8';
kbc_award_revision = 0x42;
@@ -2401,8 +2474,8 @@ kbc_at_init(const device_t *info)
case KBC_VEN_SIEMENS:
kbc_ami_revision = '8';
kbc_award_revision = 0x42;
dev->write60_ven = write60_ami;
dev->write64_ven = write64_siemens;
dev->write_cmd_data_ven = write_cmd_data_ami;
dev->write_cmd_ven = write_cmd_siemens;
break;
case KBC_VEN_ACER:
@@ -2411,24 +2484,24 @@ kbc_at_init(const device_t *info)
case KBC_VEN_IBM_PS1:
case KBC_VEN_IBM:
case KBC_VEN_COMPAQ:
dev->write64_ven = write64_generic;
dev->write_cmd_ven = write_cmd_generic;
break;
case KBC_VEN_OLIVETTI:
dev->write64_ven = write64_olivetti;
dev->write_cmd_ven = write_cmd_olivetti;
break;
case KBC_VEN_ALI:
kbc_ami_revision = 'F';
kbc_award_revision = 0x43;
dev->write60_ven = write60_ami;
dev->write64_ven = write64_ami;
dev->write_cmd_data_ven = write_cmd_data_ami;
dev->write_cmd_ven = write_cmd_ami;
break;
case KBC_VEN_TRIGEM_AMI:
kbc_ami_revision = 'Z';
dev->write60_ven = write60_ami;
dev->write64_ven = write64_ami;
dev->write_cmd_data_ven = write_cmd_data_ami;
dev->write_cmd_ven = write_cmd_ami;
break;
case KBC_VEN_AMI:
@@ -2451,23 +2524,23 @@ kbc_at_init(const device_t *info)
else
kbc_ami_revision = 'F';
dev->write60_ven = write60_ami;
dev->write64_ven = write64_ami;
dev->write_cmd_data_ven = write_cmd_data_ami;
dev->write_cmd_ven = write_cmd_ami;
break;
case KBC_VEN_PHOENIX:
dev->write60_ven = write60_phoenix;
dev->write64_ven = write64_phoenix;
dev->write_cmd_data_ven = write_cmd_data_phoenix;
dev->write_cmd_ven = write_cmd_phoenix;
break;
case KBC_VEN_QUADTEL:
dev->write60_ven = write60_quadtel;
dev->write64_ven = write64_quadtel;
dev->write_cmd_data_ven = write_cmd_data_quadtel;
dev->write_cmd_ven = write_cmd_quadtel;
break;
case KBC_VEN_TOSHIBA:
dev->write60_ven = write60_toshiba;
dev->write64_ven = write64_toshiba;
dev->write_cmd_data_ven = write_cmd_data_toshiba;
dev->write_cmd_ven = write_cmd_toshiba;
break;
default:
@@ -2493,6 +2566,8 @@ kbc_at_init(const device_t *info)
fast_reset = 0x00;
kbc_at_handler(1, 0x0060, dev);
return dev;
}

View File

@@ -30,11 +30,13 @@
#include "cpu.h"
uint8_t postcard_codes[POSTCARDS_NUM];
char postcard_diags[5] = { 0 };
static uint16_t postcard_port;
static uint8_t postcard_written[POSTCARDS_NUM];
static uint8_t postcard_ports_num = 1;
static uint8_t postcard_prev_codes[POSTCARDS_NUM];
static char postcard_prev_diags[5] = { 0 };
#define UISTR_LEN 32
static char postcard_str[UISTR_LEN]; /* UI output string */
@@ -97,6 +99,22 @@ postcard_setui(void)
ps[1][0], ps[1][1], ps[1][2], ps[1][3]);
break;
}
} else if (strstr(machines[machine].name, " Dell ")) {
char dell_diags[10] = { 0 };
if (!postcard_written[1])
snprintf(dell_diags, sizeof(dell_diags), "---- ----");
else if (postcard_written[1] == 1)
snprintf(dell_diags, sizeof(dell_diags), "%s ----", postcard_diags);
else
snprintf(dell_diags, sizeof(dell_diags), "%s %s", postcard_diags, postcard_prev_diags);
if (!postcard_written[0])
snprintf(postcard_str, sizeof(postcard_str), "POST: -- -- %s", dell_diags);
else if (postcard_written[0] == 1)
snprintf(postcard_str, sizeof(postcard_str), "POST: %02X -- %s", postcard_codes[0], dell_diags);
else
snprintf(postcard_str, sizeof(postcard_str), "POST: %02X %02X %s", postcard_codes[0], postcard_prev_codes[0], dell_diags);
} else {
if (!postcard_written[0])
snprintf(postcard_str, sizeof(postcard_str), "POST: -- --");
@@ -122,6 +140,9 @@ postcard_reset(void)
memset(postcard_codes, 0x00, POSTCARDS_NUM * sizeof(uint8_t));
memset(postcard_prev_codes, 0x00, POSTCARDS_NUM * sizeof(uint8_t));
memset(postcard_diags, 0x00, 5 * sizeof(char));
memset(postcard_prev_diags, 0x00, 5 * sizeof(char));
postcard_setui();
}
@@ -140,6 +161,35 @@ postcard_write(uint16_t port, uint8_t val, UNUSED(void *priv))
postcard_setui();
}
static int
postcard_cmp_diags(uint32_t val)
{
int ret = 0;
char *pv = (char *) &val;
for (int i = 0; i < 4; i++)
ret = ret || (pv[i] != postcard_diags[3 - i]);
return ret;
}
static void
postcard_writel(uint16_t port, uint32_t val, UNUSED(void *priv))
{
char *pv = (char *) &val;
if (postcard_written[1] && !postcard_cmp_diags(val))
return;
*(uint32_t *) postcard_prev_diags = *(uint32_t *) postcard_diags;
for (int i = 0; i < 4; i++)
postcard_diags[i] = pv[3 - i];
if (postcard_written[1] < 2)
postcard_written[1]++;
postcard_setui();
}
static void *
postcard_init(UNUSED(const device_t *info))
{
@@ -173,6 +223,10 @@ postcard_init(UNUSED(const device_t *info))
io_sethandler(postcard_port, postcard_ports_num,
NULL, NULL, NULL, postcard_write, NULL, NULL, NULL);
if (strstr(machines[machine].name, " Dell "))
io_sethandler(0x00e0, 0x0001,
NULL, NULL, NULL, NULL, NULL, postcard_writel, NULL);
return postcard_write;
}

View File

@@ -856,7 +856,7 @@ dma16_read(uint16_t addr, UNUSED(void *priv))
break;
}
dma_log("dma16_read(%08X) = %02X\n", port, ret);
dma_log("dma16_read(%08X) = %02X\n", addr, ret);
return ret;
}

View File

@@ -377,6 +377,15 @@ fdc_set_power_down(fdc_t *fdc, uint8_t power_down)
fdc->power_down = power_down;
}
void
fdc_toggle_flag(fdc_t *fdc, int flag, int on)
{
if (on)
fdc->flags |= flag;
else
fdc->flags &= ~flag;
}
void
fdc_update_max_track(fdc_t *fdc, int max_track)
{
@@ -1484,7 +1493,7 @@ fdc_read(uint16_t addr, void *priv)
fdc->step = 0;
break;
default:
ret = 0xFF;
ret = 0xff;
}
fdc_log("[%04X:%08X] Read FDC %04X %02X [%i:%02X]\n", CS, cpu_state.pc, addr, ret, drive, fdc->dor & (0x10 << drive));
return ret;
@@ -2235,9 +2244,13 @@ fdc_set_base(fdc_t *fdc, int base)
{
int super_io = (fdc->flags & FDC_FLAG_SUPERIO);
if (base == 0x0000) {
fdc->base_address = base;
return;
}
if (fdc->flags & FDC_FLAG_NSC) {
io_sethandler(base + 2, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
io_sethandler(base + 4, 0x0002, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
io_sethandler(base + 2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
io_sethandler(base + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
} else {
if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) {
@@ -2266,10 +2279,12 @@ fdc_remove(fdc_t *fdc)
{
int super_io = (fdc->flags & FDC_FLAG_SUPERIO);
if (fdc->base_address == 0x0000)
return;
fdc_log("FDC Removed (%04X)\n", fdc->base_address);
if (fdc->flags & FDC_FLAG_NSC) {
io_removehandler(fdc->base_address + 2, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
io_removehandler(fdc->base_address + 4, 0x0002, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
io_removehandler(fdc->base_address + 2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
io_removehandler(fdc->base_address + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc);
} else {
if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) {

View File

@@ -183,6 +183,7 @@ extern uint8_t fdc_get_densel_polarity(fdc_t *fdc);
extern void fdc_update_densel_force(fdc_t *fdc, int densel_force);
extern void fdc_update_drvrate(fdc_t *fdc, int drive, int drvrate);
extern void fdc_update_drv2en(fdc_t *fdc, int drv2en);
extern void fdc_toggle_flag(fdc_t *fdc, int flag, int on);
extern void fdc_noidam(fdc_t *fdc);
extern void fdc_nosector(fdc_t *fdc);

View File

@@ -289,7 +289,9 @@ extern uint8_t kbc_at_read_p(void *priv, uint8_t port, uint8_t mask);
extern void kbc_at_write_p(void *priv, uint8_t port, uint8_t mask, uint8_t val);
extern void kbc_at_set_fast_reset(uint8_t new_fast_reset);
extern void kbc_at_handler(int set, void *priv);
extern void kbc_at_port_handler(int num, int set, uint16_t port, void *priv);
extern void kbc_at_handler(int set, uint16_t port, void *priv);
extern void kbc_at_set_irq(int num, uint16_t irq, void *priv);
extern void kbc_at_dev_queue_reset(atkbc_dev_t *dev, uint8_t reset_main);
extern uint8_t kbc_at_dev_queue_pos(atkbc_dev_t *dev, uint8_t main);

View File

@@ -92,13 +92,23 @@ extern const device_t pc87332_398_ide_device;
extern const device_t pc87332_398_ide_sec_device;
extern const device_t pc87332_398_ide_fdcon_device;
#define PCX7307_PC87307 0x00c0
#define PCX7307_PC97307 0x00cf
#define PC87309_PC87309 0x00e0
#define PCX730X_CHIP_ID 0x00ff
#define PCX730X_AMI 0x0200 /* AMI '5' Megakey KBC firmware. */
#define PCX730X_PHOENIX_42 0x0500 /* Phoenix Multikey/42 1.37 KBC firmware. */
#define PCX730X_PHOENIX_42I 0x0700 /* Phoenix Multikey/42i 4.16 KBC firmware. */
#define PCX730X_KBC 0x0f00
#define PCX730X_15C 0x2000
extern const device_t pc87307_device;
extern const device_t pc87307_15c_device;
extern const device_t pc87307_both_device;
extern const device_t pc97307_device;
extern const device_t pc87309_device;
extern const device_t pc87309_15c_device;
/* LG Prime */
extern const device_t prime3b_device;

View File

@@ -229,9 +229,9 @@ void
lpt_port_setup(int i, uint16_t port)
{
if (lpt_ports[i].enabled) {
if (lpt_ports[i].addr != 0xffff)
if ((lpt_ports[i].addr != 0xffff) && (lpt_ports[i].addr != 0x0000))
io_removehandler(lpt_ports[i].addr, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
if (port != 0xffff)
if ((port != 0xffff) && (port != 0x0000))
io_sethandler(port, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]);
lpt_ports[i].addr = port;
} else

View File

@@ -584,7 +584,7 @@ machine_at_s1846_init(const machine_t *model)
pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4);
device_add(&i440bx_device);
device_add(&piix4e_device);
device_add(&pc87309_device);
device_add_params(&pc87309_device, (void *) (PCX730X_AMI | PC87309_PC87309));
device_add(&keyboard_ps2_ami_pci_device);
device_add(&intel_flash_bxt_device);
spd_register(SPD_TYPE_SDRAM, 0x7, 256);

View File

@@ -141,7 +141,7 @@ machine_at_fw6400gx_init(const machine_t *model)
device_add(&i440gx_device);
device_add(&piix4e_device);
device_add(&keyboard_ps2_ami_pci_device);
device_add(&pc87309_15c_device);
device_add_params(&pc87309_device, (void *) (PCX730X_15C | PCX730X_AMI | PC87309_PC87309));
device_add(ics9xxx_get(ICS9250_08));
device_add(&sst_flash_29ee020_device);
spd_register(SPD_TYPE_SDRAM, 0xF, 512);

View File

@@ -984,19 +984,21 @@ machine_at_optiplex_gn_init(const machine_t *model)
pci_init(PCI_CONFIG_TYPE_1);
pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4);
pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); /* Trio64V2/GX, temporarily Trio64V2/DX is given */
pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 1, 3, 4);
pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 2, 1);
pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 1, 3, 4);
pci_register_slot(0x10, PCI_CARD_VIDEO, 4, 0, 0, 0); /* Trio64V2/GX, temporarily Trio64V2/DX is given */
pci_register_slot(0x11, PCI_CARD_NETWORK, 4, 0, 0, 0); /* 3C905, not yet emulated */
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4);
if (gfxcard[0] == VID_INTERNAL)
device_add(machine_get_vid_device(machine));
if ((sound_card_current[0] == SOUND_INTERNAL) && machine_get_snd_device(machine)->available())
machine_snd = device_add(machine_get_snd_device(machine));
device_add(&i430tx_device);
device_add(&piix4_device);
device_add(&keyboard_ps2_ami_pci_device);
device_add(&pc87307_15c_device);
device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42 | PCX7307_PC87307));
device_add(&intel_flash_bxt_device);
spd_register(SPD_TYPE_SDRAM, 0x3, 128);
@@ -1040,8 +1042,7 @@ machine_at_an430tx_init(const machine_t *model)
pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3);
device_add(&i430tx_device);
device_add(&piix4_device);
device_add(&keyboard_ps2_ami_pci_device);
device_add(&pc87307_both_device);
device_add_params(&pc87307_device, (void *) (PCX730X_PHOENIX_42I | PCX7307_PC97307));
device_add(&intel_flash_bxt_ami_device);
spd_register(SPD_TYPE_SDRAM, 0x3, 128);

View File

@@ -250,8 +250,7 @@ machine_at_vs440fx_init(const machine_t *model)
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0);
device_add(&i440fx_device);
device_add(&piix3_device);
device_add(&keyboard_ps2_intel_ami_pci_device);
device_add(&pc87307_device);
device_add_params(&pc87307_device, (void *) (PCX730X_AMI | PCX7307_PC87307));
device_add(&intel_flash_bxt_ami_device);
@@ -287,8 +286,7 @@ machine_at_gw2kvenus_init(const machine_t *model)
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0);
device_add(&i440fx_device);
device_add(&piix3_device);
device_add(&keyboard_ps2_intel_ami_pci_device);
device_add(&pc87307_device);
device_add_params(&pc87307_device, (void *) (PCX730X_AMI | PCX7307_PC87307));
device_add(&intel_flash_bxt_ami_device);
@@ -324,8 +322,7 @@ machine_at_ap440fx_init(const machine_t *model)
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4);
device_add(&i440fx_device);
device_add(&piix3_device);
device_add(&keyboard_ps2_ami_pci_device);
device_add(&pc87307_device);
device_add_params(&pc87307_device, (void *) (PCX730X_AMI | PCX7307_PC87307));
device_add(&intel_flash_bxt_ami_device);
if (sound_card_current[0] == SOUND_INTERNAL)

View File

@@ -13103,11 +13103,15 @@ const machine_t machines[] = {
.snd_device = NULL,
.net_device = NULL
},
/* According to Dell specifications, it can have either National Semiconductor PC87307 or PC87309
Super I/O. All known instances have the former, although other similar Dells of the era have
pinouts for accompanying either so this likely also does.
/*
According to Dell specifications, it can have either National Semiconductor
PC87307 or PC87309 Super I/O. All known instances have the former, although
other similar Dells of the era have pinouts for accompanying either so this
likely also does.
The KBC is likely an AMIKey-2 clone. */
The KBC is either an AMI '5' MegaKey, Phoenix MultiKey/42 1.37, or Phoenix
MultiKey/42i 4.16.
*/
{
.name = "[i430TX] Dell OptiPlex GN+",
.internal_name = "optiplex_gn",
@@ -13129,7 +13133,8 @@ const machine_t machines[] = {
.max_multi = 3.5
},
.bus_flags = MACHINE_PS2_PCI,
.flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_VIDEO, /* Video: S3 86C785 (Trio64V2/GX), ethernet: 3C905 */
/* Video: S3 86C785 (Trio64V2/GX), ethernet: 3C905. */
.flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_VIDEO | MACHINE_SOUND,
.ram = {
.min = 8192,
.max = 262144,
@@ -13143,8 +13148,9 @@ const machine_t machines[] = {
.device = NULL,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = &s3_trio64v2_dx_onboard_pci_device, /* Stop-gap measure until the Trio64V2/GX is emulated, as both use the same VBIOS */
.snd_device = NULL,
/* Stop-gap measure until the Trio64V2/GX is emulated, as both use the same VBIOS. */
.vid_device = &s3_trio64v2_dx_onboard_pci_device,
.snd_device = &sb_vibra16xv_onboard_device,
.net_device = NULL
},
/* [TEST] Has AMI Megakey '5' KBC firmware on the SM(S)C FDC37C67x Super I/O chip. */

View File

@@ -1107,9 +1107,10 @@ nvr_at_init(const device_t *info)
case 1: /* standard AT */
case 5: /* AMI WinBIOS 1994 */
case 6: /* AMI BIOS 1995 */
if ((info->local & 0x1f) == 0x11)
if ((info->local & 0x1f) == 0x11) {
local->flags |= FLAG_PIIX4;
else {
local->def = 0x00;
} else {
local->def = 0x00;
if ((info->local & 0x1f) == 0x15)
local->flags |= FLAG_AMI_1994_HACK;

View File

@@ -894,7 +894,7 @@ fdc37c93x_kbc_handler(fdc37c93x_t *dev)
dev->kbc_base = local_enable ? 0x0060 : 0x0000;
if (dev->kbc_base != old_base)
kbc_at_handler(local_enable, dev->kbc);
kbc_at_handler(local_enable, dev->kbc_base, dev->kbc);
}
static void

File diff suppressed because it is too large Load Diff

View File

@@ -8,11 +8,9 @@
*
* Emulation of the NatSemi PC87309 Super I/O chip.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2020 Miran Grca.
* Copyright 2020-2025 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
@@ -24,44 +22,81 @@
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/lpt.h>
#include <86box/machine.h>
#include <86box/mem.h>
#include <86box/nvr.h>
#include <86box/pci.h>
#include <86box/rom.h>
#include <86box/serial.h>
#include <86box/hdc.h>
#include <86box/hdc_ide.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/keyboard.h>
#include <86box/sio.h>
#include <86box/plat_fallthrough.h>
#include "cpu.h"
typedef struct pc87309_t {
uint8_t id;
uint8_t baddr;
uint8_t pm_idx;
uint8_t regs[48];
uint8_t ld_regs[256][208];
uint8_t pm[8];
uint8_t baddr;
uint16_t superio_base;
uint16_t pm_base;
int cur_reg;
void *kbc;
fdc_t *fdc;
serial_t *uart[2];
} pc87309_t;
enum {
LD_FDC = 0,
LD_LPT,
LD_UART2,
LD_UART1,
LD_PM,
LD_KBD,
LD_MOUSE
} pc87309_ld_t;
#define LD_MIN LD_FDC
#define LD_MAX LD_MOUSE
static void fdc_handler(pc87309_t *dev);
static void lpt1_handler(pc87309_t *dev);
static void serial_handler(pc87309_t *dev, int uart);
static void kbc_handler(pc87309_t *dev);
static void pc87309_write(uint16_t port, uint8_t val, void *priv);
static uint8_t pc87309_read(uint16_t port, void *priv);
#ifdef ENABLE_PC87309_LOG
int pc87309_do_log = ENABLE_PC87309_LOG;
static void
pc87309_log(const char *fmt, ...)
{
va_list ap;
if (pc87309_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define pc87309_log(fmt, ...)
#endif
static void
pc87309_pm_write(uint16_t port, uint8_t val, void *priv)
{
pc87309_t *dev = (pc87309_t *) priv;
if (port & 1) {
if (port & 1)
dev->pm[dev->pm_idx] = val;
else {
dev->pm_idx = val & 0x07;
switch (dev->pm_idx) {
case 0x00:
@@ -74,8 +109,7 @@ pc87309_pm_write(uint16_t port, uint8_t val, void *priv)
default:
break;
}
} else
dev->pm_idx = val & 0x07;
}
}
uint8_t
@@ -109,43 +143,48 @@ pc87309_pm_init(pc87309_t *dev, uint16_t addr)
}
static void
superio_handler(pc87309_t *dev)
kbc_handler(pc87309_t *dev)
{
io_removehandler(0x15c, 0x0002,
pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev);
io_removehandler(0x02e, 0x0002,
pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev);
uint8_t active = (dev->ld_regs[LD_KBD][0x00] & 0x01) &&
(dev->pm[0x00] & 0x01);
uint8_t active_2 = dev->ld_regs[LD_MOUSE][0x00] & 0x01;
uint8_t irq = (dev->ld_regs[LD_KBD][0x40] & 0x0f);
uint8_t irq_2 = (dev->ld_regs[LD_MOUSE][0x40] & 0x0f);
uint16_t addr = (dev->ld_regs[LD_KBD][0x30] << 8) |
dev->ld_regs[LD_KBD][0x31];
uint16_t addr_2 = (dev->ld_regs[LD_KBD][0x32] << 8) |
dev->ld_regs[LD_KBD][0x33];
switch (dev->regs[0x21] & 0x0b) {
case 0x02:
case 0x08:
case 0x0a:
io_sethandler(0x15c, 0x0002,
pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev);
break;
case 0x03:
case 0x09:
case 0x0b:
io_sethandler(0x02e, 0x0002,
pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev);
break;
pc87309_log("%02X, %02X, %02X, %02X, %04X, %04X\n",
active, active_2, irq, irq_2, addr, addr_2);
if (addr <= 0xfff8) {
pc87309_log("Enabling KBC #1 on %04X...\n", addr);
kbc_at_port_handler(0, active, addr, dev->kbc);
}
if (addr_2 <= 0xfff8) {
pc87309_log("Enabling KBC #2 on %04X...\n", addr_2);
kbc_at_port_handler(1, active, addr_2, dev->kbc);
}
kbc_at_set_irq(0, active ? irq : 0xffff, dev->kbc);
kbc_at_set_irq(1, (active && active_2) ? irq_2 : 0xffff, dev->kbc);
}
static void
fdc_handler(pc87309_t *dev)
{
uint8_t irq;
uint8_t active;
uint16_t addr;
fdc_remove(dev->fdc);
active = (dev->ld_regs[0x00][0x00] & 0x01) && (dev->pm[0x00] & 0x08);
addr = ((dev->ld_regs[0x00][0x30] << 8) | dev->ld_regs[0x00][0x31]) - 0x0002;
irq = (dev->ld_regs[0x00][0x40] & 0x0f);
uint8_t active = (dev->ld_regs[LD_FDC][0x00] & 0x01) &&
(dev->pm[0x00] & 0x08);
uint8_t irq = (dev->ld_regs[LD_FDC][0x40] & 0x0f);
uint16_t addr = ((dev->ld_regs[LD_FDC][0x30] << 8) |
dev->ld_regs[LD_FDC][0x31]) & 0xfff8;
if (active) {
if (active && (addr <= 0xfff8)) {
pc87309_log("Enabling FDC on %04X, IRQ %i...\n", addr, irq);
fdc_set_base(dev->fdc, addr);
fdc_set_irq(dev->fdc, irq);
}
@@ -154,222 +193,351 @@ fdc_handler(pc87309_t *dev)
static void
lpt1_handler(pc87309_t *dev)
{
uint8_t irq;
uint8_t active;
uint16_t addr;
uint8_t active = (dev->ld_regs[LD_LPT][0x00] & 0x01) &&
(dev->pm[0x00] & 0x10);
uint8_t irq = (dev->ld_regs[LD_LPT][0x40] & 0x0f);
uint16_t addr = (dev->ld_regs[LD_LPT][0x30] << 8) |
dev->ld_regs[LD_LPT][0x31];
lpt1_remove();
active = (dev->ld_regs[0x01][0x00] & 0x01) && (dev->pm[0x00] & 0x10);
addr = (dev->ld_regs[0x01][0x30] << 8) | dev->ld_regs[0x01][0x31];
irq = (dev->ld_regs[0x01][0x40] & 0x0f);
if (active) {
if (active && (addr <= 0xfffc)) {
pc87309_log("Enabling LPT1 on %04X...\n", addr);
lpt1_setup(addr);
lpt1_irq(irq);
}
} else
lpt1_setup(0xffff);
lpt1_irq(irq);
}
static void
serial_handler(pc87309_t *dev, int uart)
{
uint8_t irq;
uint8_t active;
uint16_t addr;
serial_remove(dev->uart[uart]);
active = (dev->ld_regs[0x03 - uart][0x00] & 0x01) && (dev->pm[0x00] & (1 << (6 - uart)));
addr = (dev->ld_regs[0x03 - uart][0x30] << 8) | dev->ld_regs[0x03 - uart][0x31];
irq = (dev->ld_regs[0x03 - uart][0x40] & 0x0f);
uint8_t active = (dev->ld_regs[LD_UART1 - uart][0x00] & 0x01) &&
(dev->pm[0x00] & (1 << (6 - uart)));
uint8_t irq = (dev->ld_regs[LD_UART1 - uart][0x40] & 0x0f);
uint16_t addr = (dev->ld_regs[LD_UART1 - uart][0x30] << 8) |
dev->ld_regs[LD_UART1 - uart][0x31];
if (active)
if (active && (addr <= 0xfff8)) {
pc87309_log("Enabling COM%i on %04X...\n", uart + 1, addr);
serial_setup(dev->uart[uart], addr, irq);
} else
serial_setup(dev->uart[uart], 0x0000, irq);
}
static void
pm_handler(pc87309_t *dev)
{
uint8_t active;
uint16_t addr;
pc87309_pm_remove(dev);
active = (dev->ld_regs[0x04][0x00] & 0x01);
addr = (dev->ld_regs[0x04][0x30] << 8) | dev->ld_regs[0x04][0x31];
uint8_t active = (dev->ld_regs[LD_PM][0x00] & 0x01);
uint16_t addr = (dev->ld_regs[LD_PM][0x30] << 8) |
dev->ld_regs[LD_PM][0x31];
if (active)
if (active) {
pc87309_log("Enabling power management on %04X...\n", addr);
pc87309_pm_init(dev, addr);
}
}
static void
superio_handler(pc87309_t *dev)
{
if (dev->superio_base != 0x0000)
io_removehandler(dev->superio_base, 0x0002,
pc87309_read, NULL, NULL,
pc87309_write, NULL, NULL, dev);
switch (dev->regs[0x22] & 0x0b) {
default:
dev->superio_base = 0x0000;
break;
case 0x02:
case 0x08: case 0x0a:
dev->superio_base = 0x015c;
break;
case 0x03:
case 0x09: case 0x0b:
dev->superio_base = 0x002e;
break;
}
if (dev->superio_base != 0x0000) {
pc87309_log("Enabling Super I/O on %04X...\n", dev->superio_base);
io_sethandler(dev->superio_base, 0x0002,
pc87309_read, NULL, NULL,
pc87309_write, NULL, NULL, dev);
}
}
static void
pc87309_write(uint16_t port, uint8_t val, void *priv)
{
pc87309_t *dev = (pc87309_t *) priv;
uint8_t index;
index = (port & 1) ? 0 : 1;
pc87309_t *dev = (pc87309_t *) priv;
uint8_t ld = dev->regs[0x07];
uint8_t reg = dev->cur_reg - 0x30;
uint8_t index = (port & 1) ? 0 : 1;
uint8_t old = dev->regs[dev->cur_reg];
if (index) {
dev->cur_reg = val;
return;
} else {
#ifdef ENABLE_PC87309_LOG
if (dev->cur_reg >= 0x30)
pc87309_log("[%04X:%08X] [W] (%04X) %02X:%02X = %02X\n",
CS, cpu_state.pc, port, ld, dev->cur_reg, val);
else
pc87309_log("[%04X:%08X] [W] (%04X) %02X = %02X\n",
CS, cpu_state.pc, port, dev->cur_reg, val);
#endif
switch (dev->cur_reg) {
case 0x00:
case 0x02:
case 0x03:
case 0x06:
case 0x07:
case 0x02: case 0x03:
case 0x06: case 0x07:
dev->regs[dev->cur_reg] = val;
break;
case 0x21:
dev->regs[dev->cur_reg] = val;
fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, !!(val & 0x04));
superio_handler(dev);
break;
case 0x22:
dev->regs[dev->cur_reg] = val & 0x7f;
dev->regs[dev->cur_reg] = val;
break;
default:
if (dev->cur_reg >= 0x30) {
if ((dev->regs[0x07] != 0x06) || !(dev->regs[0x21] & 0x10))
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val;
}
if (dev->cur_reg >= 0x30)
old = dev->ld_regs[ld][reg];
break;
}
}
switch (dev->cur_reg) {
case 0x30:
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x01;
switch (dev->regs[0x07]) {
case 0x00:
switch (ld) {
default:
break;
case LD_KBD: case LD_MOUSE:
dev->ld_regs[ld][reg] = val;
kbc_handler(dev);
break;
case LD_FDC:
dev->ld_regs[ld][reg] = val;
fdc_handler(dev);
break;
case 0x01:
case LD_LPT:
dev->ld_regs[ld][reg] = val;
lpt1_handler(dev);
break;
case 0x02:
case LD_UART2:
dev->ld_regs[ld][reg] = val;
serial_handler(dev, 1);
break;
case 0x03:
case LD_UART1:
dev->ld_regs[ld][reg] = val;
serial_handler(dev, 0);
break;
case 0x04:
case LD_PM:
dev->ld_regs[ld][reg] = val;
pm_handler(dev);
break;
default:
break;
}
break;
/* I/O Range Check. */
case 0x31:
switch (ld) {
default:
break;
case LD_MIN ... LD_MAX:
if (ld != LD_MOUSE)
dev->ld_regs[ld][reg] = val;
break;
}
break;
/* Base Address 0 MSB. */
case 0x60:
case 0x62:
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x07;
if (dev->cur_reg == 0x62)
break;
switch (dev->regs[0x07]) {
case 0x00:
switch (ld) {
default:
break;
case LD_KBD:
dev->ld_regs[ld][reg] = val;
kbc_handler(dev);
break;
case LD_FDC:
dev->ld_regs[ld][reg] = val;
fdc_handler(dev);
break;
case 0x01:
case LD_LPT:
dev->ld_regs[ld][reg] = (old & 0xfc) | (val & 0x03);
lpt1_handler(dev);
break;
case 0x02:
case LD_UART2:
dev->ld_regs[ld][reg] = val;
serial_handler(dev, 1);
break;
case 0x03:
case LD_UART1:
dev->ld_regs[ld][reg] = val;
serial_handler(dev, 0);
break;
case 0x04:
case LD_PM:
dev->ld_regs[ld][reg] = val;
pm_handler(dev);
break;
default:
break;
}
break;
case 0x63:
if (dev->regs[0x07] == 0x06)
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xf8) | 0x04;
break;
/* Base Address 0 LSB. */
case 0x61:
switch (dev->regs[0x07]) {
case 0x00:
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfa) | 0x02;
switch (ld) {
default:
break;
case LD_KBD:
dev->ld_regs[ld][reg] = (old & 0x04) | (val & 0xfb);
kbc_handler(dev);
break;
case LD_FDC:
dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8);
fdc_handler(dev);
break;
case 0x01:
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfc;
case LD_LPT:
dev->ld_regs[ld][reg] = (old & 0x03) | (val & 0xfc);
lpt1_handler(dev);
break;
case 0x02:
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8;
case LD_UART2:
dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8);
serial_handler(dev, 1);
break;
case 0x03:
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8;
case LD_UART1:
dev->ld_regs[ld][reg] = (old & 0x07) | (val & 0xf8);
serial_handler(dev, 0);
break;
case 0x04:
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfe;
case LD_PM:
dev->ld_regs[ld][reg] = (old & 0x01) | (val & 0xfe);
pm_handler(dev);
break;
case 0x06:
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf8;
break;
default:
break;
}
break;
/* Base Address 1 MSB (undocumented for Logical Device 7). */
case 0x62:
switch (ld) {
default:
break;
case LD_KBD:
dev->ld_regs[ld][reg] = val;
kbc_handler(dev);
break;
}
break;
/* Base Address 1 LSB (undocumented for Logical Device 7). */
case 0x63:
switch (ld) {
default:
break;
case LD_KBD:
dev->ld_regs[ld][reg] = (old & 0x04) | (val & 0xfb);
kbc_handler(dev);
break;
}
break;
/* Interrupt Select. */
case 0x70:
case 0x74:
case 0x75:
switch (dev->regs[0x07]) {
case 0x00:
switch (ld) {
default:
break;
case LD_KBD: case LD_MOUSE:
dev->ld_regs[ld][reg] = val;
kbc_handler(dev);
break;
case LD_FDC:
dev->ld_regs[ld][reg] = val;
fdc_handler(dev);
break;
case 0x01:
case LD_LPT:
dev->ld_regs[ld][reg] = val;
lpt1_handler(dev);
break;
case 0x02:
case LD_UART2:
dev->ld_regs[ld][reg] = val;
serial_handler(dev, 1);
break;
case 0x03:
case LD_UART1:
dev->ld_regs[ld][reg] = val;
serial_handler(dev, 0);
break;
case 0x04:
pm_handler(dev);
break;
default:
break;
}
break;
/* Interrupt Type. */
case 0x71:
switch (ld) {
default:
break;
case LD_MIN ... LD_MAX:
if ((ld == LD_KBD) || (ld == LD_MOUSE))
dev->ld_regs[ld][reg] = (old & 0xfc) | (val & 0x03);
else
dev->ld_regs[ld][reg] = (old & 0xfd) | (val & 0x02);
break;
}
break;
/* DMA Channel Select 0. */
case 0x74:
switch (ld) {
default:
break;
case LD_FDC:
dev->ld_regs[ld][reg] = val;
fdc_handler(dev);
break;
case LD_LPT:
dev->ld_regs[ld][reg] = val;
lpt1_handler(dev);
break;
case LD_UART2:
dev->ld_regs[ld][reg] = val;
break;
}
break;
/* DMA Channel Select 1. */
case 0x75:
switch (ld) {
default:
break;
case LD_UART2:
dev->ld_regs[ld][reg] = val;
break;
}
break;
/* Configuration Register 0. */
case 0xf0:
switch (dev->regs[0x07]) {
case 0x00:
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xe1;
switch (ld) {
default:
break;
case LD_KBD:
dev->ld_regs[ld][reg] = val;
break;
case LD_FDC:
dev->ld_regs[ld][reg] = val;
fdc_update_densel_polarity(dev->fdc, (val & 0x20) ? 1 : 0);
fdc_update_enh_mode(dev->fdc, (val & 0x40) ? 1 : 0);
break;
case 0x01:
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xf3;
case LD_LPT:
dev->ld_regs[ld][reg] = val;
lpt1_handler(dev);
break;
case 0x02:
case 0x03:
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x87;
break;
case 0x06:
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xc1;
break;
default:
case LD_UART2: case LD_UART1:
dev->ld_regs[ld][reg] = val;
break;
}
break;
/* Configuration Register 1. */
case 0xf1:
if (dev->regs[0x07] == 0x00)
dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0x0f;
switch (ld) {
default:
break;
case LD_FDC:
dev->ld_regs[ld][reg] = val;
break;
}
break;
default:
@@ -377,30 +545,44 @@ pc87309_write(uint16_t port, uint8_t val, void *priv)
}
}
uint8_t
static uint8_t
pc87309_read(uint16_t port, void *priv)
{
const pc87309_t *dev = (pc87309_t *) priv;
uint8_t ret = 0xff;
uint8_t index;
index = (port & 1) ? 0 : 1;
const pc87309_t *dev = (pc87309_t *) priv;
uint8_t ld = dev->regs[0x07];
uint8_t reg = dev->cur_reg - 0x30;
uint8_t index = (port & 1) ? 0 : 1;
uint8_t ret = 0xff;
if (index)
ret = dev->cur_reg & 0x1f;
ret = dev->cur_reg;
else {
if (dev->cur_reg >= 0x30)
ret = dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30];
ret = dev->ld_regs[ld][reg];
/* Write-only registers. */
else if ((dev->cur_reg == 0x00) ||
(dev->cur_reg == 0x02) || (dev->cur_reg == 0x03))
ret = 0x00;
else
ret = dev->regs[dev->cur_reg];
#ifdef ENABLE_PC87309_LOG
if (dev->cur_reg >= 0x30)
pc87309_log("[%04X:%08X] [R] (%04X) %02X:%02X = %02X\n",
CS, cpu_state.pc, port, ld, dev->cur_reg, ret);
else
pc87309_log("[%04X:%08X] [R] (%04X) %02X = %02X\n",
CS, cpu_state.pc, port, dev->cur_reg, ret);
#endif
}
return ret;
}
void
pc87309_reset(pc87309_t *dev)
pc87309_reset(void *priv)
{
pc87309_t *dev = (pc87309_t *) priv;
memset(dev->regs, 0x00, 0x30);
for (uint16_t i = 0; i < 256; i++)
memset(dev->ld_regs[i], 0x00, 0xd0);
@@ -409,65 +591,56 @@ pc87309_reset(pc87309_t *dev)
dev->regs[0x20] = dev->id;
dev->regs[0x21] = 0x04 | dev->baddr;
dev->ld_regs[0x00][0x01] = 0x01;
dev->ld_regs[0x00][0x30] = 0x03;
dev->ld_regs[0x00][0x31] = 0xf2;
dev->ld_regs[0x00][0x40] = 0x06;
dev->ld_regs[0x00][0x41] = 0x03;
dev->ld_regs[0x00][0x44] = 0x02;
dev->ld_regs[0x00][0x45] = 0x04;
dev->ld_regs[0x00][0xc0] = 0x02;
dev->ld_regs[LD_KBD ][0x00] = 0x01;
dev->ld_regs[LD_KBD ][0x31] = 0x60;
dev->ld_regs[LD_KBD ][0x33] = 0x64;
dev->ld_regs[LD_KBD ][0x40] = 0x01;
dev->ld_regs[LD_KBD ][0x41] = 0x02;
dev->ld_regs[LD_KBD ][0x44] = 0x04;
dev->ld_regs[LD_KBD ][0x45] = 0x04;
dev->ld_regs[LD_KBD ][0xc0] = 0x40;
dev->ld_regs[0x01][0x30] = 0x02;
dev->ld_regs[0x01][0x31] = 0x78;
dev->ld_regs[0x01][0x40] = 0x07;
dev->ld_regs[0x01][0x44] = 0x04;
dev->ld_regs[0x01][0x45] = 0x04;
dev->ld_regs[0x01][0xc0] = 0xf2;
dev->ld_regs[LD_MOUSE][0x40] = 0x0c;
dev->ld_regs[LD_MOUSE][0x41] = 0x02;
dev->ld_regs[LD_MOUSE][0x44] = 0x04;
dev->ld_regs[LD_MOUSE][0x45] = 0x04;
dev->ld_regs[0x02][0x30] = 0x02;
dev->ld_regs[0x02][0x31] = 0xf8;
dev->ld_regs[0x02][0x40] = 0x03;
dev->ld_regs[0x02][0x41] = 0x03;
dev->ld_regs[0x02][0x44] = 0x04;
dev->ld_regs[0x02][0x45] = 0x04;
dev->ld_regs[0x02][0xc0] = 0x02;
dev->ld_regs[LD_FDC ][0x01] = 0x01;
dev->ld_regs[LD_FDC ][0x30] = 0x03;
dev->ld_regs[LD_FDC ][0x31] = 0xf0;
dev->ld_regs[LD_FDC ][0x32] = 0x03;
dev->ld_regs[LD_FDC ][0x33] = 0xf7;
dev->ld_regs[LD_FDC ][0x40] = 0x06;
dev->ld_regs[LD_FDC ][0x41] = 0x03;
dev->ld_regs[LD_FDC ][0x44] = 0x02;
dev->ld_regs[LD_FDC ][0x45] = 0x04;
dev->ld_regs[LD_FDC ][0xc0] = 0x02;
dev->ld_regs[0x03][0x30] = 0x03;
dev->ld_regs[0x03][0x31] = 0xf8;
dev->ld_regs[0x03][0x40] = 0x04;
dev->ld_regs[0x03][0x41] = 0x03;
dev->ld_regs[0x03][0x44] = 0x04;
dev->ld_regs[0x03][0x45] = 0x04;
dev->ld_regs[0x03][0xc0] = 0x02;
dev->ld_regs[LD_LPT ][0x30] = 0x02;
dev->ld_regs[LD_LPT ][0x31] = 0x78;
dev->ld_regs[LD_LPT ][0x40] = 0x07;
dev->ld_regs[LD_LPT ][0x44] = 0x04;
dev->ld_regs[LD_LPT ][0x45] = 0x04;
dev->ld_regs[LD_LPT ][0xc0] = 0xf2;
dev->ld_regs[0x04][0x44] = 0x04;
dev->ld_regs[0x04][0x45] = 0x04;
dev->ld_regs[LD_UART2][0x30] = 0x02;
dev->ld_regs[LD_UART2][0x31] = 0xf8;
dev->ld_regs[LD_UART2][0x40] = 0x03;
dev->ld_regs[LD_UART2][0x41] = 0x03;
dev->ld_regs[LD_UART2][0x44] = 0x04;
dev->ld_regs[LD_UART2][0x45] = 0x04;
dev->ld_regs[LD_UART2][0xc0] = 0x02;
dev->ld_regs[0x05][0x40] = 0x0c;
dev->ld_regs[0x05][0x41] = 0x02;
dev->ld_regs[0x05][0x44] = 0x04;
dev->ld_regs[0x05][0x45] = 0x04;
dev->ld_regs[LD_UART1][0x30] = 0x03;
dev->ld_regs[LD_UART1][0x31] = 0xf8;
dev->ld_regs[LD_UART1][0x40] = 0x04;
dev->ld_regs[LD_UART1][0x41] = 0x03;
dev->ld_regs[LD_UART1][0x44] = 0x04;
dev->ld_regs[LD_UART1][0x45] = 0x04;
dev->ld_regs[LD_UART1][0xc0] = 0x02;
dev->ld_regs[0x06][0x01] = 0x01;
dev->ld_regs[0x06][0x31] = 0x60;
dev->ld_regs[0x06][0x33] = 0x64;
dev->ld_regs[0x06][0x40] = 0x01;
dev->ld_regs[0x06][0x41] = 0x02;
dev->ld_regs[0x06][0x44] = 0x04;
dev->ld_regs[0x06][0x45] = 0x04;
dev->ld_regs[0x06][0xc0] = 0x40;
dev->regs[0x00] = 0x0B;
dev->regs[0x01] = 0x01;
dev->regs[0x03] = 0x01;
dev->regs[0x05] = 0x0D;
dev->regs[0x08] = 0x70;
dev->regs[0x09] = 0xC0;
dev->regs[0x0b] = 0x80;
dev->regs[0x0f] = 0x1E;
dev->regs[0x12] = 0x30;
dev->regs[0x19] = 0xEF;
dev->ld_regs[LD_PM ][0x44] = 0x04;
dev->ld_regs[LD_PM ][0x45] = 0x04;
dev->pm[0] = 0x79;
dev->pm[4] = 0x0e;
@@ -478,11 +651,15 @@ pc87309_reset(pc87309_t *dev)
0 = 360 rpm @ 500 kbps for 3.5"
1 = Default, 300 rpm @ 500, 300, 250, 1000 kbps for 3.5"
*/
lpt1_remove();
serial_remove(dev->uart[0]);
serial_remove(dev->uart[1]);
fdc_toggle_flag(dev->fdc, FDC_FLAG_PS2_MCA, 0);
fdc_reset(dev->fdc);
kbc_handler(dev);
fdc_handler(dev);
lpt1_handler(dev);
serial_handler(dev, 0);
serial_handler(dev, 1);
pm_handler(dev);
superio_handler(dev);
}
@@ -503,7 +680,27 @@ pc87309_init(const device_t *info)
dev->fdc = device_add(&fdc_at_nsc_device);
dev->baddr = (info->local & 0x100) ? 8 : 9;
dev->uart[0] = device_add_inst(&ns16550_device, 1);
dev->uart[1] = device_add_inst(&ns16550_device, 2);
switch (info->local & PCX730X_KBC) {
default:
case PCX730X_AMI:
dev->kbc = device_add(&keyboard_ps2_intel_ami_pci_device);
break;
/* Optiplex! */
case PCX730X_PHOENIX_42:
dev->kbc = device_add(&keyboard_ps2_phoenix_device);
break;
case PCX730X_PHOENIX_42I:
dev->kbc = device_add(&keyboard_ps2_phoenix_pci_device);
break;
}
if (info->local & PCX730X_15C)
dev->baddr = 0x0a;
else
dev->baddr = 0x0b;
pc87309_reset(dev);
@@ -514,24 +711,10 @@ const device_t pc87309_device = {
.name = "National Semiconductor PC87309 Super I/O",
.internal_name = "pc87309",
.flags = 0,
.local = 0xe0,
.local = 0,
.init = pc87309_init,
.close = pc87309_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t pc87309_15c_device = {
.name = "National Semiconductor PC87309 Super I/O (Port 15Ch)",
.internal_name = "pc87309_15c",
.flags = 0,
.local = 0x1e0,
.init = pc87309_init,
.close = pc87309_close,
.reset = NULL,
.reset = pc87309_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,