mirror of
https://github.com/86Box/86Box.git
synced 2026-02-25 04:45:31 -07:00
PC87306 Super I/O chip fixes, fixes #6428.
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
|
||||
typedef struct pc87306_t {
|
||||
uint8_t tries;
|
||||
uint8_t cfg_lock;
|
||||
uint8_t regs[29];
|
||||
uint8_t gpio[2];
|
||||
uint16_t gpioba;
|
||||
@@ -125,6 +126,7 @@ lpt_handler(pc87306_t *dev)
|
||||
uint8_t lpt_irq = LPT2_IRQ;
|
||||
uint8_t cnfgb_readout = 0x08;
|
||||
|
||||
pclog("Removing LPT port...\n");
|
||||
lpt_port_remove(dev->lpt);
|
||||
|
||||
temp = dev->regs[0x01] & 3;
|
||||
@@ -155,6 +157,9 @@ lpt_handler(pc87306_t *dev)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(dev->regs[0x00] & 0x01))
|
||||
lpt_port = 0x000;
|
||||
|
||||
if (dev->regs[0x1b] & 0x10)
|
||||
lpt_irq = (dev->regs[0x1b] & 0x20) ? 7 : 5;
|
||||
|
||||
@@ -167,8 +172,10 @@ lpt_handler(pc87306_t *dev)
|
||||
lpt_set_epp(dev->lpt, !!(dev->regs[0x04] & 0x01));
|
||||
lpt_set_ecp(dev->lpt, !!(dev->regs[0x04] & 0x04));
|
||||
|
||||
if (lpt_port)
|
||||
if (lpt_port) {
|
||||
pclog("Setting up LPT port at %04X...\n", lpt_port);
|
||||
lpt_port_setup(dev->lpt, lpt_port);
|
||||
}
|
||||
|
||||
lpt_port_irq(dev->lpt, lpt_irq);
|
||||
|
||||
@@ -187,18 +194,20 @@ serial_handler(pc87306_t *dev, int uart)
|
||||
uint8_t pnp_shift;
|
||||
uint8_t irq;
|
||||
|
||||
temp = (dev->regs[0x01] >> (2 << uart)) & 3;
|
||||
serial_remove(dev->uart[uart]);
|
||||
|
||||
fer_shift = 2 << uart; /* 2 for UART 1, 4 for UART 2 */
|
||||
pnp_shift = 2 + (uart << 2); /* 2 for UART 1, 6 for UART 2 */
|
||||
|
||||
temp = (dev->regs[0x01] >> fer_shift) & 3;
|
||||
|
||||
/* 0 = COM1 (IRQ 4), 1 = COM2 (IRQ 3), 2 = COM3 (IRQ 4), 3 = COM4 (IRQ 3) */
|
||||
fer_irq = ((dev->regs[1] >> fer_shift) & 1) ? 3 : 4;
|
||||
pnp1_irq = ((dev->regs[0x1c] >> pnp_shift) & 1) ? 4 : 3;
|
||||
|
||||
irq = (dev->regs[0x1c] & 1) ? pnp1_irq : fer_irq;
|
||||
|
||||
switch (temp) {
|
||||
if (dev->regs[0x00] & fer_shift) switch (temp) {
|
||||
case 0:
|
||||
serial_setup(dev->uart[uart], COM1_ADDR, irq);
|
||||
break;
|
||||
@@ -273,13 +282,15 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
||||
return;
|
||||
} else {
|
||||
if (dev->tries) {
|
||||
if ((dev->cur_reg == 0) && (val == 8))
|
||||
val = 0x4b;
|
||||
if (dev->cfg_lock)
|
||||
return;
|
||||
|
||||
valxor = val ^ dev->regs[dev->cur_reg];
|
||||
dev->tries = 0;
|
||||
if ((dev->cur_reg <= 28) && (dev->cur_reg != 8)) {
|
||||
if (dev->cur_reg == 0)
|
||||
val &= 0x5f;
|
||||
if ((dev->cur_reg <= 0x1c) && (dev->cur_reg != 0x08)) {
|
||||
if ((dev->cur_reg == 0x00) && (val == 0x08))
|
||||
val = 0x4f;
|
||||
|
||||
dev->regs[dev->cur_reg] = val;
|
||||
} else
|
||||
return;
|
||||
@@ -291,21 +302,12 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
||||
|
||||
switch (dev->cur_reg) {
|
||||
case 0x00:
|
||||
if (valxor & 0x01) {
|
||||
lpt_port_remove(dev->lpt);
|
||||
if ((val & 1) && !(dev->regs[0x02] & 1))
|
||||
lpt_handler(dev);
|
||||
}
|
||||
if (valxor & 0x02) {
|
||||
serial_remove(dev->uart[0x00]);
|
||||
if ((val & 2) && !(dev->regs[0x02] & 1))
|
||||
serial_handler(dev, 0);
|
||||
}
|
||||
if (valxor & 0x04) {
|
||||
serial_remove(dev->uart[0x01]);
|
||||
if ((val & 4) && !(dev->regs[0x02] & 1))
|
||||
serial_handler(dev, 1);
|
||||
}
|
||||
if (valxor & 0x01)
|
||||
lpt_handler(dev);
|
||||
if (valxor & 0x02)
|
||||
serial_handler(dev, 0);
|
||||
if (valxor & 0x04)
|
||||
serial_handler(dev, 1);
|
||||
if (valxor & 0x28) {
|
||||
fdc_remove(dev->fdc);
|
||||
if ((val & 8) && !(dev->regs[0x02] & 1))
|
||||
@@ -313,52 +315,24 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
if (valxor & 0x03) {
|
||||
lpt_port_remove(dev->lpt);
|
||||
if ((dev->regs[0x00] & 1) && !(dev->regs[0x02] & 1))
|
||||
lpt_handler(dev);
|
||||
}
|
||||
if (valxor & 0xcc) {
|
||||
serial_remove(dev->uart[0x00]);
|
||||
if ((dev->regs[0x00] & 2) && !(dev->regs[0x02] & 1))
|
||||
serial_handler(dev, 0);
|
||||
}
|
||||
if (valxor & 0xf0) {
|
||||
serial_remove(dev->uart[0x01]);
|
||||
if ((dev->regs[0x00] & 4) && !(dev->regs[0x02] & 1))
|
||||
serial_handler(dev, 1);
|
||||
}
|
||||
if (valxor & 0x03)
|
||||
lpt_handler(dev);
|
||||
if (valxor & 0xcc)
|
||||
serial_handler(dev, 0);
|
||||
if (valxor & 0xf0)
|
||||
serial_handler(dev, 1);
|
||||
break;
|
||||
case 0x02:
|
||||
if (valxor & 0x01) {
|
||||
lpt_port_remove(dev->lpt);
|
||||
serial_remove(dev->uart[0x00]);
|
||||
serial_remove(dev->uart[0x01]);
|
||||
fdc_remove(dev->fdc);
|
||||
|
||||
if (!(val & 1)) {
|
||||
if (dev->regs[0x00] & 0x01)
|
||||
lpt_handler(dev);
|
||||
if (dev->regs[0x00] & 0x02)
|
||||
serial_handler(dev, 0);
|
||||
if (dev->regs[0x00] & 0x04)
|
||||
serial_handler(dev, 1);
|
||||
if (dev->regs[0x00] & 0x08)
|
||||
fdc_set_base(dev->fdc, (dev->regs[0x00] & 0x20) ? FDC_SECONDARY_ADDR : FDC_PRIMARY_ADDR);
|
||||
}
|
||||
}
|
||||
if (valxor & 0x88) {
|
||||
lpt_port_remove(dev->lpt);
|
||||
if ((dev->regs[0x00] & 1) && !(dev->regs[0x02] & 1))
|
||||
lpt_handler(dev);
|
||||
}
|
||||
if (valxor & 0x01)
|
||||
fdc_set_power_down(dev->fdc, val & 0x01);
|
||||
if (valxor & 0x40)
|
||||
dev->cfg_lock = val & 0x40;
|
||||
if (valxor & 0x88)
|
||||
lpt_handler(dev);
|
||||
break;
|
||||
case 0x04:
|
||||
if (valxor & (0x05)) {
|
||||
lpt_port_remove(dev->lpt);
|
||||
if ((dev->regs[0x00] & 0x01) && !(dev->regs[0x02] & 0x01))
|
||||
lpt_handler(dev);
|
||||
}
|
||||
if (valxor & (0x05))
|
||||
lpt_handler(dev);
|
||||
if (valxor & 0x80)
|
||||
nvr_lock_set(0x00, 256, !!(val & 0x80), dev->nvr);
|
||||
break;
|
||||
@@ -389,37 +363,24 @@ pc87306_write(uint16_t port, uint8_t val, void *priv)
|
||||
pc87306_gpio_handler(dev);
|
||||
break;
|
||||
case 0x18:
|
||||
if (valxor & (0x0e)) {
|
||||
lpt_port_remove(dev->lpt);
|
||||
if ((dev->regs[0x00] & 0x01) && !(dev->regs[0x02] & 0x01))
|
||||
lpt_handler(dev);
|
||||
}
|
||||
if (valxor & (0x0e))
|
||||
lpt_handler(dev);
|
||||
break;
|
||||
case 0x19:
|
||||
if (valxor) {
|
||||
lpt_port_remove(dev->lpt);
|
||||
if ((dev->regs[0x00] & 1) && !(dev->regs[0x02] & 1))
|
||||
lpt_handler(dev);
|
||||
}
|
||||
if (valxor)
|
||||
lpt_handler(dev);
|
||||
break;
|
||||
case 0x1b:
|
||||
if (valxor & 0x70) {
|
||||
lpt_port_remove(dev->lpt);
|
||||
if (!(val & 0x40))
|
||||
dev->regs[0x19] = 0xef;
|
||||
if ((dev->regs[0x00] & 1) && !(dev->regs[0x02] & 1))
|
||||
lpt_handler(dev);
|
||||
lpt_handler(dev);
|
||||
}
|
||||
break;
|
||||
case 0x1c:
|
||||
if (valxor) {
|
||||
serial_remove(dev->uart[0x00]);
|
||||
serial_remove(dev->uart[0x01]);
|
||||
|
||||
if ((dev->regs[0x00] & 2) && !(dev->regs[0x02] & 1))
|
||||
serial_handler(dev, 0);
|
||||
if ((dev->regs[0x00] & 4) && !(dev->regs[0x02] & 1))
|
||||
serial_handler(dev, 1);
|
||||
serial_handler(dev, 0);
|
||||
serial_handler(dev, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -437,15 +398,17 @@ pc87306_read(uint16_t port, void *priv)
|
||||
|
||||
index = (port & 1) ? 0 : 1;
|
||||
|
||||
if (dev->tries == 0xff) {
|
||||
ret = 0x88;
|
||||
dev->tries = 0xfe;
|
||||
} else if (dev->tries == 0xfe) {
|
||||
ret = 0x00;
|
||||
dev->tries = 0;
|
||||
} else if (index) {
|
||||
ret = dev->cur_reg & 0x1f;
|
||||
dev->tries = 0;
|
||||
if (index) {
|
||||
if (dev->tries == 0xff) {
|
||||
ret = 0x88;
|
||||
dev->tries = 0xfe;
|
||||
} else if (dev->tries == 0xfe) {
|
||||
ret = 0x00;
|
||||
dev->tries = 0;
|
||||
} else {
|
||||
ret = dev->cur_reg & 0x1f;
|
||||
dev->tries = 0;
|
||||
}
|
||||
} else {
|
||||
if (dev->cur_reg == 8)
|
||||
ret = 0x70;
|
||||
@@ -462,30 +425,27 @@ pc87306_reset_common(void *priv)
|
||||
{
|
||||
pc87306_t *dev = (pc87306_t *) priv;
|
||||
|
||||
memset(dev->regs, 0, 29);
|
||||
|
||||
memset(dev->regs, 0x00, 29);
|
||||
dev->tries = 0xff;
|
||||
|
||||
dev->regs[0x00] = 0x0B;
|
||||
dev->regs[0x01] = 0x01;
|
||||
dev->regs[0x00] = 0x00;
|
||||
dev->regs[0x01] = 0x10;
|
||||
dev->regs[0x02] = 0x08;
|
||||
dev->regs[0x03] = 0x01;
|
||||
dev->regs[0x05] = 0x0D;
|
||||
dev->regs[0x05] = 0x0d;
|
||||
dev->regs[0x08] = 0x70;
|
||||
dev->regs[0x09] = 0xC0;
|
||||
dev->regs[0x09] = 0xc0;
|
||||
dev->regs[0x0b] = 0x80;
|
||||
dev->regs[0x0f] = 0x1E;
|
||||
dev->regs[0x0f] = 0x1e;
|
||||
dev->regs[0x12] = 0x30;
|
||||
dev->regs[0x19] = 0xEF;
|
||||
dev->regs[0x19] = 0xef;
|
||||
|
||||
/*
|
||||
0 = 360 rpm @ 500 kbps for 3.5"
|
||||
1 = Default, 300 rpm @ 500, 300, 250, 1000 kbps for 3.5"
|
||||
*/
|
||||
lpt_set_cnfga_readout(dev->lpt, 0x10);
|
||||
lpt_port_remove(dev->lpt);
|
||||
lpt_handler(dev);
|
||||
serial_remove(dev->uart[0x00]);
|
||||
serial_remove(dev->uart[0x01]);
|
||||
serial_handler(dev, 0);
|
||||
serial_handler(dev, 1);
|
||||
fdc_reset(dev->fdc);
|
||||
@@ -495,6 +455,8 @@ pc87306_reset_common(void *priv)
|
||||
nvr_at_handler(1, 0x0070, dev->nvr);
|
||||
nvr_bank_set(0, 0, dev->nvr);
|
||||
nvr_wp_set(0, 0, dev->nvr);
|
||||
|
||||
dev->cfg_lock = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user