Improve VIA 686 Super I/O and hardware monitor to match probed hardware behavior
This commit is contained in:
@@ -29,18 +29,17 @@
|
|||||||
|
|
||||||
#define CLAMP(a, min, max) (((a) < (min)) ? (min) : (((a) > (max)) ? (max) : (a)))
|
#define CLAMP(a, min, max) (((a) < (min)) ? (min) : (((a) > (max)) ? (max) : (a)))
|
||||||
#define VT82C686_RPM_TO_REG(r, d) ((r) ? CLAMP(1350000 / (r * d), 1, 255) : 0)
|
#define VT82C686_RPM_TO_REG(r, d) ((r) ? CLAMP(1350000 / (r * d), 1, 255) : 0)
|
||||||
/* Temperature/voltage formulas and factors derived from Linux's via686a.c driver */
|
/* Temperature/voltage formulas and factors derived from Linux's via686a.c driver. */
|
||||||
#define VT82C686_TEMP_TO_REG(t) (-1.160370e-10*(t*t*t*t*t*t) + 3.193693e-08*(t*t*t*t*t) - 1.464447e-06*(t*t*t*t) - 2.525453e-04*(t*t*t) + 1.424593e-02*(t*t) + 2.148941e+00*t + 7.275808e+01)
|
#define VT82C686_TEMP_TO_REG(t) (-1.160370e-10*(t*t*t*t*t*t) + 3.193693e-08*(t*t*t*t*t) - 1.464447e-06*(t*t*t*t) - 2.525453e-04*(t*t*t) + 1.424593e-02*(t*t) + 2.148941e+00*t + 7.275808e+01)
|
||||||
#define VT82C686_VOLTAGE_TO_REG(v, f) CLAMP((((v) * (2.628 / (f))) - 120.5) / 25, 0, 255)
|
#define VT82C686_VOLTAGE_TO_REG(v, f) CLAMP((((v) * (2.628 / (f))) - 120.5) / 25, 0, 255)
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
hwm_values_t *values;
|
hwm_values_t *values;
|
||||||
device_t *lm75[2];
|
|
||||||
|
|
||||||
uint8_t enable;
|
uint8_t enable;
|
||||||
uint16_t io_base;
|
uint16_t io_base;
|
||||||
uint8_t regs[80];
|
uint8_t regs[128];
|
||||||
} vt82c686_t;
|
} vt82c686_t;
|
||||||
|
|
||||||
|
|
||||||
@@ -59,6 +58,11 @@ vt82c686_read(uint16_t addr, void *priv)
|
|||||||
addr -= dev->io_base;
|
addr -= dev->io_base;
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
|
case 0x00 ... 0x0f: case 0x50 ... 0x7f: /* undefined registers */
|
||||||
|
/* Real 686B returns the contents of 0x40. */
|
||||||
|
ret = dev->regs[0x40];
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x1f: case 0x20: case 0x21: /* temperatures */
|
case 0x1f: case 0x20: case 0x21: /* temperatures */
|
||||||
ret = VT82C686_TEMP_TO_REG(dev->values->temperatures[(addr == 0x1f) ? 2 : (addr & 1)]);
|
ret = VT82C686_TEMP_TO_REG(dev->values->temperatures[(addr == 0x1f) ? 2 : (addr & 1)]);
|
||||||
break;
|
break;
|
||||||
@@ -84,14 +88,26 @@ static void
|
|||||||
vt82c686_write(uint16_t port, uint8_t val, void *priv)
|
vt82c686_write(uint16_t port, uint8_t val, void *priv)
|
||||||
{
|
{
|
||||||
vt82c686_t *dev = (vt82c686_t *) priv;
|
vt82c686_t *dev = (vt82c686_t *) priv;
|
||||||
uint8_t reg = port - dev->io_base;
|
uint8_t reg = port & 0x7f;
|
||||||
|
|
||||||
if ((reg == 0x41) || (reg == 0x42) || (reg == 0x45) || (reg == 0x46) || (reg == 0x48) || (reg == 0x4a) || (reg >= 0x4c))
|
switch (reg) {
|
||||||
return;
|
case 0x00 ... 0x0f:
|
||||||
|
case 0x3f: case 0x41: case 0x42: case 0x4a:
|
||||||
|
case 0x4c ... 0x7f:
|
||||||
|
/* Read-only registers. */
|
||||||
|
return;
|
||||||
|
|
||||||
if ((reg == 0x40) && (val & 0x80)) {
|
case 0x40:
|
||||||
val &= 0x7f;
|
/* Reset if requested. */
|
||||||
vt82c686_reset(dev, 1);
|
if (val & 0x80) {
|
||||||
|
vt82c686_reset(dev, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x48:
|
||||||
|
val &= 0x7f;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->regs[reg] = val;
|
dev->regs[reg] = val;
|
||||||
@@ -106,7 +122,7 @@ vt82c686_hwm_write(uint8_t addr, uint8_t val, void *priv)
|
|||||||
vt82c686_t *dev = (vt82c686_t *) priv;
|
vt82c686_t *dev = (vt82c686_t *) priv;
|
||||||
|
|
||||||
if (dev->io_base)
|
if (dev->io_base)
|
||||||
io_removehandler(dev->io_base, 0x0050,
|
io_removehandler(dev->io_base, 128,
|
||||||
vt82c686_read, NULL, NULL, vt82c686_write, NULL, NULL, dev);
|
vt82c686_read, NULL, NULL, vt82c686_write, NULL, NULL, dev);
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
@@ -126,7 +142,7 @@ vt82c686_hwm_write(uint8_t addr, uint8_t val, void *priv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dev->enable && dev->io_base)
|
if (dev->enable && dev->io_base)
|
||||||
io_sethandler(dev->io_base, 0x0050,
|
io_sethandler(dev->io_base, 128,
|
||||||
vt82c686_read, NULL, NULL, vt82c686_write, NULL, NULL, dev);
|
vt82c686_read, NULL, NULL, vt82c686_write, NULL, NULL, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,8 +150,10 @@ vt82c686_hwm_write(uint8_t addr, uint8_t val, void *priv)
|
|||||||
static void
|
static void
|
||||||
vt82c686_reset(vt82c686_t *dev, uint8_t initialization)
|
vt82c686_reset(vt82c686_t *dev, uint8_t initialization)
|
||||||
{
|
{
|
||||||
memset(dev->regs, 0, 80);
|
memset(dev->regs, 0, sizeof(dev->regs));
|
||||||
|
|
||||||
|
dev->regs[0x17] = 0x80;
|
||||||
|
dev->regs[0x3f] = 0xa2;
|
||||||
dev->regs[0x40] = 0x08;
|
dev->regs[0x40] = 0x08;
|
||||||
dev->regs[0x47] = 0x50;
|
dev->regs[0x47] = 0x50;
|
||||||
dev->regs[0x4b] = 0x15;
|
dev->regs[0x4b] = 0x15;
|
||||||
|
@@ -34,7 +34,8 @@
|
|||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t cur_reg, regs[32], fdc_dma, fdc_irq, uart_irq[2], lpt_dma, lpt_irq;
|
uint8_t cur_reg, last_val, regs[25],
|
||||||
|
fdc_dma, fdc_irq, uart_irq[2], lpt_dma, lpt_irq;
|
||||||
fdc_t *fdc;
|
fdc_t *fdc;
|
||||||
serial_t *uart[2];
|
serial_t *uart[2];
|
||||||
} vt82c686_t;
|
} vt82c686_t;
|
||||||
@@ -43,10 +44,10 @@ typedef struct {
|
|||||||
static uint8_t
|
static uint8_t
|
||||||
get_lpt_length(vt82c686_t *dev)
|
get_lpt_length(vt82c686_t *dev)
|
||||||
{
|
{
|
||||||
uint8_t length = 4;
|
uint8_t length = 4; /* non-EPP */
|
||||||
|
|
||||||
if ((dev->regs[0x02] & 0x03) == 0x2)
|
if ((dev->regs[0x02] & 0x03) == 0x02)
|
||||||
length = 8;
|
length = 8; /* EPP */
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
@@ -64,6 +65,7 @@ vt82c686_fdc_handler(vt82c686_t *dev)
|
|||||||
|
|
||||||
fdc_set_dma_ch(dev->fdc, dev->fdc_dma);
|
fdc_set_dma_ch(dev->fdc, dev->fdc_dma);
|
||||||
fdc_set_irq(dev->fdc, dev->fdc_irq);
|
fdc_set_irq(dev->fdc, dev->fdc_irq);
|
||||||
|
fdc_set_swap(dev->fdc, dev->regs[0x16] & 0x01);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -73,16 +75,20 @@ vt82c686_lpt_handler(vt82c686_t *dev)
|
|||||||
uint16_t io_mask, io_base = dev->regs[0x06] << 2;
|
uint16_t io_mask, io_base = dev->regs[0x06] << 2;
|
||||||
int io_len = get_lpt_length(dev);
|
int io_len = get_lpt_length(dev);
|
||||||
io_base &= (0xff8 | io_len);
|
io_base &= (0xff8 | io_len);
|
||||||
io_mask = 0x3fc;
|
io_mask = 0x3fc; /* non-EPP */
|
||||||
if (io_len == 8)
|
if (io_len == 8)
|
||||||
io_mask = 0x3f8;
|
io_mask = 0x3f8; /* EPP */
|
||||||
|
|
||||||
lpt1_remove();
|
lpt1_remove();
|
||||||
|
|
||||||
if (((dev->regs[0x02] & 0x03) != 0x03) && (io_base >= 0x100) && (io_base <= io_mask))
|
if (((dev->regs[0x02] & 0x03) != 0x03) && (io_base >= 0x100) && (io_base <= io_mask))
|
||||||
lpt1_init(io_base);
|
lpt1_init(io_base);
|
||||||
|
|
||||||
lpt1_irq(dev->lpt_irq);
|
if (dev->lpt_irq) {
|
||||||
|
lpt1_irq(dev->lpt_irq);
|
||||||
|
} else {
|
||||||
|
lpt1_irq(0xff);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -91,8 +97,8 @@ vt82c686_serial_handler(vt82c686_t *dev, int uart)
|
|||||||
{
|
{
|
||||||
serial_remove(dev->uart[uart]);
|
serial_remove(dev->uart[uart]);
|
||||||
|
|
||||||
if (dev->regs[0x02] & (uart ? 0x08 : 0x04))
|
if (dev->regs[0x02] & (0x04 << uart))
|
||||||
serial_setup(dev->uart[uart], (dev->regs[0x07 + uart] & 0xfe) << 2, dev->uart_irq[uart]);
|
serial_setup(dev->uart[uart], dev->regs[0x07 + uart] << 2, dev->uart_irq[uart]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -101,25 +107,31 @@ vt82c686_write(uint16_t port, uint8_t val, void *priv)
|
|||||||
{
|
{
|
||||||
vt82c686_t *dev = (vt82c686_t *) priv;
|
vt82c686_t *dev = (vt82c686_t *) priv;
|
||||||
|
|
||||||
|
/* Store last written value for echo (see comment on read). */
|
||||||
|
dev->last_val = val;
|
||||||
|
|
||||||
|
/* Write current register index on port 0. */
|
||||||
if (!(port & 1)) {
|
if (!(port & 1)) {
|
||||||
dev->cur_reg = val;
|
dev->cur_reg = val;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: Registers are [0xE0:0xFF] but we store them as [0x00:0x1F]. */
|
/* NOTE: Registers are [0xE0:0xF8] but we store them as [0x00:0x18]. */
|
||||||
if (dev->cur_reg < 0xe0)
|
if ((dev->cur_reg < 0xe0) || (dev->cur_reg > 0xf8))
|
||||||
return;
|
return;
|
||||||
uint8_t reg = dev->cur_reg & 0x1f;
|
uint8_t reg = dev->cur_reg & 0x1f;
|
||||||
|
|
||||||
/* Read-only registers */
|
/* Read-only registers. */
|
||||||
if ((reg < 0x02) || (reg == 0x04) || (reg == 0x05) || ((reg >= 0x09) && (reg < 0x0e)) ||
|
if ((reg < 0x02) || (reg == 0x0c))
|
||||||
(reg == 0x13) || (reg == 0x15) || (reg == 0x17) || (reg >= 0x19))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Write current register value on port 1. */
|
||||||
dev->regs[reg] = val;
|
dev->regs[reg] = val;
|
||||||
|
|
||||||
|
/* Update device state. */
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case 0x02:
|
case 0x02:
|
||||||
|
dev->regs[reg] &= 0xbf;
|
||||||
vt82c686_lpt_handler(dev);
|
vt82c686_lpt_handler(dev);
|
||||||
vt82c686_serial_handler(dev, 0);
|
vt82c686_serial_handler(dev, 0);
|
||||||
vt82c686_serial_handler(dev, 1);
|
vt82c686_serial_handler(dev, 1);
|
||||||
@@ -127,19 +139,54 @@ vt82c686_write(uint16_t port, uint8_t val, void *priv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x03:
|
case 0x03:
|
||||||
|
dev->regs[reg] &= 0xfc;
|
||||||
vt82c686_fdc_handler(dev);
|
vt82c686_fdc_handler(dev);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x04:
|
||||||
|
dev->regs[reg] &= 0xfc;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x05:
|
||||||
|
dev->regs[reg] |= 0x03;
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x06:
|
case 0x06:
|
||||||
vt82c686_lpt_handler(dev);
|
vt82c686_lpt_handler(dev);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x07:
|
case 0x07: case 0x08:
|
||||||
vt82c686_serial_handler(dev, 0);
|
dev->regs[reg] &= 0xfe;
|
||||||
|
vt82c686_serial_handler(dev, reg == 0x08);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x08:
|
case 0x0d:
|
||||||
vt82c686_serial_handler(dev, 1);
|
dev->regs[reg] &= 0x0f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0f:
|
||||||
|
dev->regs[reg] &= 0x7f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x10:
|
||||||
|
dev->regs[reg] &= 0xf4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x11:
|
||||||
|
dev->regs[reg] &= 0x3f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x13:
|
||||||
|
dev->regs[reg] &= 0xfb;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x14: case 0x17:
|
||||||
|
dev->regs[reg] &= 0xfe;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x16:
|
||||||
|
dev->regs[reg] &= 0xf7;
|
||||||
|
vt82c686_fdc_handler(dev);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,17 +196,16 @@ static uint8_t
|
|||||||
vt82c686_read(uint16_t port, void *priv)
|
vt82c686_read(uint16_t port, void *priv)
|
||||||
{
|
{
|
||||||
vt82c686_t *dev = (vt82c686_t *) priv;
|
vt82c686_t *dev = (vt82c686_t *) priv;
|
||||||
uint8_t ret = 0xff;
|
|
||||||
|
|
||||||
/* NOTE: Registers are [0xE0:0xFF] but we store them as [0x00:0x1F]. */
|
/* NOTE: Registers are [0xE0:0xF8] but we store them as [0x00:0x18].
|
||||||
|
Real 686B echoes the last read/written value when reading from
|
||||||
|
registers outside that range. */
|
||||||
if (!(port & 1))
|
if (!(port & 1))
|
||||||
ret = dev->cur_reg;
|
dev->last_val = dev->cur_reg;
|
||||||
else if (dev->cur_reg < 0xe0)
|
else if ((dev->cur_reg >= 0xe0) && (dev->cur_reg <= 0xf8))
|
||||||
ret = 0xff;
|
dev->last_val = dev->regs[dev->cur_reg & 0x1f];
|
||||||
else
|
|
||||||
ret = dev->regs[dev->cur_reg & 0x1f];
|
|
||||||
|
|
||||||
return ret;
|
return dev->last_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -205,7 +251,7 @@ static void
|
|||||||
vt82c686_reset(vt82c686_t *dev)
|
vt82c686_reset(vt82c686_t *dev)
|
||||||
{
|
{
|
||||||
memset(dev->regs, 0, 20);
|
memset(dev->regs, 0, 20);
|
||||||
|
|
||||||
dev->regs[0x00] = 0x3c;
|
dev->regs[0x00] = 0x3c;
|
||||||
dev->regs[0x02] = 0x03;
|
dev->regs[0x02] = 0x03;
|
||||||
dev->regs[0x03] = 0xfc;
|
dev->regs[0x03] = 0xfc;
|
||||||
|
Reference in New Issue
Block a user