Merge pull request #1049 from richardg867/master

Hardware monitoring overhaul
This commit is contained in:
Miran Grča
2020-10-31 03:01:12 +01:00
committed by GitHub
20 changed files with 685 additions and 886 deletions

View File

@@ -70,12 +70,12 @@ acpi_update_irq(void *priv)
if (dev->irq_mode == 1)
pci_set_irq(dev->slot, dev->irq_pin);
else
picintlevel(1 << dev->irq_line);
pci_set_mirq(0xf0 | dev->irq_line, 1);
} else {
if (dev->irq_mode == 1)
pci_clear_irq(dev->slot, dev->irq_pin);
else
picintc(1 << dev->irq_line);
pci_clear_mirq(0xf0 | dev->irq_line, 1);
}
}

View File

@@ -491,7 +491,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv)
if (val & 0x01)
trc_write(0x0047, (val & 0x80) ? 0x06 : 0x04, NULL);
pic_set_shadow(!!(val & 0x10));
pic_elcr_set_enabled(!!(val & 0x20));
pic_elcr_io_handler(!!(val & 0x20));
dev->pci_isa_regs[0x47] = val & 0xfe;
break;
case 0x48:
@@ -511,31 +511,38 @@ pipc_write(int func, int addr, uint8_t val, void *priv)
pci_set_irq_level(PCI_INTB, !(val & 4));
pci_set_irq_level(PCI_INTC, !(val & 2));
pci_set_irq_level(PCI_INTD, !(val & 1));
dev->pci_isa_regs[0x54] = val & 0x0f;
break;
case 0x55:
pipc_log("PIPC: PCI INT%c %d\n", (dev->local >= VIA_PIPC_596A) ? 'A' : 'D', val >> 4);
pipc_log("PIPC: Steering PIRQ%c to IRQ %d\n", (dev->local >= VIA_PIPC_596A) ? 'A' : 'D', val >> 4);
pci_set_irq_routing((dev->local >= VIA_PIPC_596A) ? PCI_INTA : PCI_INTD, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
if (dev->local <= VIA_PIPC_586B)
if (dev->local <= VIA_PIPC_586B) {
pipc_log("PIPC: Steering MIRQ0 to IRQ %d\n", val & 0x0f);
pci_set_mirq_routing(PCI_MIRQ0, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
}
dev->pci_isa_regs[0x55] = val;
break;
case 0x56:
pipc_log("PIPC: PCI INT%c %d\n", (dev->local >= VIA_PIPC_596A) ? 'C' : 'A', val >> 4);
pipc_log("PIPC: PCI INTB %d\n", val & 0x0f);
break;
case 0x56:
pipc_log("PIPC: Steering PIRQ%c to IRQ %d\n", (dev->local >= VIA_PIPC_596A) ? 'C' : 'A', val >> 4);
pipc_log("PIPC: Steering PIRQB to IRQ %d\n", val & 0x0f);
pci_set_irq_routing((dev->local >= VIA_PIPC_596A) ? PCI_INTC : PCI_INTA, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
pci_set_irq_routing(PCI_INTB, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
dev->pci_isa_regs[0x56] = val;
break;
case 0x57:
pipc_log("PIPC: PCI INT%c %d\n", (dev->local >= VIA_PIPC_596A) ? 'D' : 'C', val >> 4);
pipc_log("PIPC: Steering PIRQ%c to IRQ %d\n", (dev->local >= VIA_PIPC_596A) ? 'D' : 'C', val >> 4);
pci_set_irq_routing((dev->local >= VIA_PIPC_596A) ? PCI_INTD : PCI_INTC, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
if (dev->local <= VIA_PIPC_586B)
if (dev->local <= VIA_PIPC_586B) {
pipc_log("PIPC: Steering MIRQ1 to IRQ %d\n", val & 0x0f);
pci_set_mirq_routing(PCI_MIRQ1, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
}
dev->pci_isa_regs[0x57] = val;
break;
case 0x58:
if (dev->local == VIA_PIPC_586B)
if (dev->local == VIA_PIPC_586B) {
pipc_log("PIPC: Steering MIRQ2 to IRQ %d\n", val & 0x0f);
pci_set_mirq_routing(PCI_MIRQ2, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
}
dev->pci_isa_regs[0x58] = val;
break;
case 0x5b:
@@ -754,7 +761,9 @@ pipc_write(int func, int addr, uint8_t val, void *priv)
break;
case 0x42:
dev->power_regs[addr] = (dev->power_regs[0x42] & ~0x0f) | (val & 0x0f);
dev->power_regs[addr] &= ~0x0f;
dev->power_regs[addr] |= val & 0x0f;
acpi_set_irq_line(dev->acpi, dev->power_regs[addr]);
break;
case 0x61: case 0x62: case 0x63:

View File

@@ -15,23 +15,81 @@
* Copyright 2020 RichardG.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include "cpu.h"
#include <86box/machine.h>
#include <86box/hwm.h>
hwm_values_t hwm_values;
/* Refer to specific hardware monitor implementations for the meaning of hwm_values. */
hwm_values_t hwm_values;
void
hwm_set_values(hwm_values_t new_values)
uint16_t
hwm_get_vcore()
{
hwm_values = new_values;
}
/* Determine Vcore for the active CPU. */
CPU *cpu = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective];
switch (cpu->cpu_type) {
case CPU_WINCHIP:
case CPU_WINCHIP2:
#if defined(DEV_BRANCH) && defined(USE_AMD_K5)
case CPU_K5:
case CPU_5K86:
#endif
#if (defined(USE_NEW_DYNAREC) || (defined(DEV_BRANCH) && defined(USE_CYRIX_6X86)))
case CPU_Cx6x86:
#endif
return 3520;
case CPU_PENTIUMMMX:
return ((cpu->cpuid_model & 0xf000) == 0x1000) ? 3300 : 2800;
hwm_values_t*
hwm_get_values()
{
return &hwm_values;
#if (defined(USE_NEW_DYNAREC) || (defined(DEV_BRANCH) && defined(USE_CYRIX_6X86)))
case CPU_Cx6x86MX:
return (cpu->rspeed == 208333333) ? 2700 : 2900;
case CPU_Cx6x86L:
#endif
case CPU_PENTIUM2:
return 2800;
case CPU_K6_2C:
if (cpu->multi == 5.0)
return 2400;
else if (cpu->rspeed >= 550000000)
return 2300;
else
return 2200;
case CPU_K6:
if ((cpu->cpuid_model & 0x0f0) == 0x070)
return 2200;
else if (cpu->multi <= 3.0)
return 2900;
else
return 3200;
case CPU_K6_2:
case CPU_K6_3:
return 2200;
case CPU_PENTIUM2D:
case CPU_CYRIX3S:
return 2050;
case CPU_K6_2P:
case CPU_K6_3P:
return 2000;
default:
return 3300;
}
}

View File

@@ -24,7 +24,6 @@
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include "cpu.h"
#include <86box/smbus.h>
#include <86box/hwm.h>
@@ -83,14 +82,14 @@ gl518sm_remap(gl518sm_t *dev, uint8_t addr)
gl518sm_log("GL518SM: remapping to SMBus %02Xh\n", addr);
smbus_removehandler(dev->smbus_addr, 1,
gl518sm_smbus_read_byte, gl518sm_smbus_read_byte_cmd, gl518sm_smbus_read_word_cmd, NULL,
gl518sm_smbus_write_byte, gl518sm_smbus_write_byte_cmd, gl518sm_smbus_write_word_cmd, NULL,
dev);
gl518sm_smbus_read_byte, gl518sm_smbus_read_byte_cmd, gl518sm_smbus_read_word_cmd, NULL,
gl518sm_smbus_write_byte, gl518sm_smbus_write_byte_cmd, gl518sm_smbus_write_word_cmd, NULL,
dev);
if (addr < 0x80) smbus_sethandler(addr, 1,
gl518sm_smbus_read_byte, gl518sm_smbus_read_byte_cmd, gl518sm_smbus_read_word_cmd, NULL,
gl518sm_smbus_write_byte, gl518sm_smbus_write_byte_cmd, gl518sm_smbus_write_word_cmd, NULL,
dev);
gl518sm_smbus_read_byte, gl518sm_smbus_read_byte_cmd, gl518sm_smbus_read_word_cmd, NULL,
gl518sm_smbus_write_byte, gl518sm_smbus_write_byte_cmd, gl518sm_smbus_write_word_cmd, NULL,
dev);
dev->smbus_addr = addr;
}
@@ -126,13 +125,14 @@ gl518sm_read(gl518sm_t *dev, uint8_t reg)
uint16_t ret = dev->regs[reg & 0x1f];
switch (reg) {
case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c:
/* two-byte registers: leave as-is */
break;
default:
/* single-byte registers: duplicate low byte to high byte (real hardware behavior unknown) */
ret |= (ret << 8);
break;
case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c:
/* two-byte registers: leave as-is */
break;
default:
/* single-byte registers: duplicate low byte to high byte (real hardware behavior unknown) */
ret |= (ret << 8);
break;
}
gl518sm_log("GL518SM: read(%02X) = %04X\n", reg, ret);
@@ -171,36 +171,36 @@ gl518sm_write(gl518sm_t *dev, uint8_t reg, uint16_t val)
gl518sm_log("GL518SM: write(%02X, %04X)\n", reg, val);
switch (reg) {
case 0x00: case 0x01: case 0x04: case 0x07: case 0x0d: case 0x12: case 0x13: case 0x14: case 0x15:
/* read-only registers */
return 0;
case 0x00: case 0x01: case 0x04: case 0x07: case 0x0d: case 0x12: case 0x13: case 0x14: case 0x15:
/* read-only registers */
return 0;
case 0x0a:
dev->regs[0x13] = (val & 0xff);
break;
case 0x0a:
dev->regs[0x13] = (val & 0xff);
break;
case 0x03:
dev->regs[reg] = (val & 0xfc);
case 0x03:
dev->regs[reg] = (val & 0xfc);
if (val & 0x80) /* Init */
gl518sm_reset(dev);
break;
if (val & 0x80) /* Init */
gl518sm_reset(dev);
break;
case 0x0f:
dev->regs[reg] = (val & 0xf8);
case 0x0f:
dev->regs[reg] = (val & 0xf8);
/* update fan values to match the new divisor */
dev->regs[0x07] = (GL518SM_RPM_TO_REG(dev->values->fans[0], 1 << ((dev->regs[0x0f] >> 6) & 0x3)) << 8);
dev->regs[0x07] |= GL518SM_RPM_TO_REG(dev->values->fans[1], 1 << ((dev->regs[0x0f] >> 4) & 0x3));
break;
/* update fan values to match the new divisor */
dev->regs[0x07] = (GL518SM_RPM_TO_REG(dev->values->fans[0], 1 << ((dev->regs[0x0f] >> 6) & 0x3)) << 8);
dev->regs[0x07] |= GL518SM_RPM_TO_REG(dev->values->fans[1], 1 << ((dev->regs[0x0f] >> 4) & 0x3));
break;
case 0x11:
dev->regs[reg] = (val & 0x7f);
break;
case 0x11:
dev->regs[reg] = (val & 0x7f);
break;
default:
dev->regs[reg] = val;
break;
default:
dev->regs[reg] = val;
break;
}
return 1;
@@ -250,7 +250,22 @@ gl518sm_init(const device_t *info)
memset(dev, 0, sizeof(gl518sm_t));
dev->local = info->local;
dev->values = hwm_get_values();
/* Set default values. */
hwm_values_t defaults = {
{ /* fan speeds */
3000, /* System */
3000 /* CPU */
}, { /* temperatures */
30 /* CPU */
}, { /* voltages */
hwm_get_vcore(), /* Vcore */
RESISTOR_DIVIDER(12000, 150, 47), /* +12V (15K/4.7K divider suggested in the GL518SM datasheet) */
3300 /* +3.3V */
}
};
hwm_values = defaults;
dev->values = &hwm_values;
gl518sm_reset(dev);
gl518sm_remap(dev, dev->local & 0x7f);
@@ -259,6 +274,7 @@ gl518sm_init(const device_t *info)
}
/* GL518SM on SMBus address 2Ch */
const device_t gl518sm_2c_device = {
"Genesys Logic GL518SM Hardware Monitor",
DEVICE_ISA,
@@ -268,6 +284,7 @@ const device_t gl518sm_2c_device = {
NULL
};
/* GL518SM on SMBus address 2Dh */
const device_t gl518sm_2d_device = {
"Genesys Logic GL518SM Hardware Monitor",
DEVICE_ISA,

View File

@@ -65,14 +65,14 @@ lm75_remap(lm75_t *dev, uint8_t addr)
lm75_log("LM75: remapping to SMBus %02Xh\n", addr);
if (dev->smbus_addr < 0x80) smbus_removehandler(dev->smbus_addr, 1,
lm75_smbus_read_byte, lm75_smbus_read_byte_cmd, lm75_smbus_read_word_cmd, NULL,
lm75_smbus_write_byte, lm75_smbus_write_byte_cmd, lm75_smbus_write_word_cmd, NULL,
dev);
lm75_smbus_read_byte, lm75_smbus_read_byte_cmd, lm75_smbus_read_word_cmd, NULL,
lm75_smbus_write_byte, lm75_smbus_write_byte_cmd, lm75_smbus_write_word_cmd, NULL,
dev);
if (addr < 0x80) smbus_sethandler(addr, 1,
lm75_smbus_read_byte, lm75_smbus_read_byte_cmd, lm75_smbus_read_word_cmd, NULL,
lm75_smbus_write_byte, lm75_smbus_write_byte_cmd, lm75_smbus_write_word_cmd, NULL,
dev);
lm75_smbus_read_byte, lm75_smbus_read_byte_cmd, lm75_smbus_read_word_cmd, NULL,
lm75_smbus_write_byte, lm75_smbus_write_byte_cmd, lm75_smbus_write_word_cmd, NULL,
dev);
dev->smbus_addr = addr;
}
@@ -101,21 +101,21 @@ lm75_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv)
uint8_t retlo = 0;
switch (cmd & 0x3) {
case 0x0: /* temperature */
rethi = lm75_read(dev, 0x0);
retlo = lm75_read(dev, 0x1);
break;
case 0x1: /* configuration */
rethi = retlo = lm75_read(dev, 0x2);
break;
case 0x2: /* Thyst */
rethi = lm75_read(dev, 0x3);
retlo = lm75_read(dev, 0x4);
break;
case 0x3: /* Tos */
rethi = lm75_read(dev, 0x5);
retlo = lm75_read(dev, 0x6);
break;
case 0x0: /* temperature */
rethi = lm75_read(dev, 0x0);
retlo = lm75_read(dev, 0x1);
break;
case 0x1: /* configuration */
rethi = retlo = lm75_read(dev, 0x2);
break;
case 0x2: /* Thyst */
rethi = lm75_read(dev, 0x3);
retlo = lm75_read(dev, 0x4);
break;
case 0x3: /* Tos */
rethi = lm75_read(dev, 0x5);
retlo = lm75_read(dev, 0x6);
break;
}
return (retlo << 8) | rethi; /* byte-swapped for some reason */
@@ -131,9 +131,13 @@ lm75_read(lm75_t *dev, uint8_t reg)
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal SMBus call, if necessary. */
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_smbus_addr < 0x80))
ret = smbus_read_byte_cmd(dev->as99127f_smbus_addr, reg);
ret = smbus_read_byte_cmd(dev->as99127f_smbus_addr, reg);
else if ((reg & 0x7) == 0x0) /* temperature high byte */
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]) >> 8;
else if ((reg & 0x7) == 0x1) /* temperature low byte */
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]);
else
ret = dev->regs[reg & 0x7];
ret = dev->regs[reg & 0x7];
lm75_log("LM75: read(%02X) = %02X\n", reg, ret);
@@ -165,22 +169,22 @@ lm75_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv)
uint8_t vallo = (val & 0xff);
switch (cmd & 0x3) {
case 0x0: /* temperature */
lm75_write(dev, 0x0, valhi);
lm75_write(dev, 0x1, vallo);
break;
case 0x1: /* configuration */
lm75_write(dev, 0x2, vallo);
break;
case 0x2: /* Thyst */
lm75_write(dev, 0x3, valhi);
lm75_write(dev, 0x4, vallo);
break;
case 0x3: /* Tos */
lm75_write(dev, 0x5, valhi);
lm75_write(dev, 0x6, vallo);
break;
break;
case 0x0: /* temperature */
lm75_write(dev, 0x0, valhi);
lm75_write(dev, 0x1, vallo);
break;
case 0x1: /* configuration */
lm75_write(dev, 0x2, vallo);
break;
case 0x2: /* Thyst */
lm75_write(dev, 0x3, valhi);
lm75_write(dev, 0x4, vallo);
break;
case 0x3: /* Tos */
lm75_write(dev, 0x5, valhi);
lm75_write(dev, 0x6, vallo);
break;
break;
}
}
@@ -194,14 +198,14 @@ lm75_write(lm75_t *dev, uint8_t reg, uint8_t val)
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal SMBus call, if necessary. */
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_smbus_addr < 0x80)) {
smbus_write_byte_cmd(dev->as99127f_smbus_addr, reg, val);
return 1;
smbus_write_byte_cmd(dev->as99127f_smbus_addr, reg, val);
return 1;
}
uint8_t reg_idx = (reg & 0x7);
if ((reg_idx <= 0x1) || (reg_idx == 0x7))
return 0; /* read-only registers */
return 0; /* read-only registers */
dev->regs[reg_idx] = val;
@@ -212,9 +216,6 @@ lm75_write(lm75_t *dev, uint8_t reg, uint8_t val)
static void
lm75_reset(lm75_t *dev)
{
uint16_t temp = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]);
dev->regs[0x0] = (temp >> 8);
dev->regs[0x1] = temp;
dev->regs[0x3] = 0x4b;
dev->regs[0x5] = 0x50;
@@ -240,7 +241,11 @@ lm75_init(const device_t *info)
memset(dev, 0, sizeof(lm75_t));
dev->local = info->local;
dev->values = hwm_get_values();
/* Set default value. */
if (dev->local)
hwm_values.temperatures[dev->local >> 8] = 30;
dev->values = &hwm_values;
dev->as99127f_smbus_addr = 0x80;
@@ -253,7 +258,7 @@ lm75_init(const device_t *info)
/* LM75 on SMBus address 4Ah, reporting temperatures[1]. */
const device_t lm75_1_4a_device = {
"National Semiconductor LM75 Temperature Sensor",
DEVICE_AT,
DEVICE_ISA,
0x14a,
lm75_init, lm75_close, NULL,
NULL, NULL, NULL,
@@ -265,7 +270,7 @@ const device_t lm75_1_4a_device = {
the Winbond W83781D family. Not to be used stand-alone. */
const device_t lm75_w83781d_device = {
"Winbond W83781D Secondary Temperature Sensor",
DEVICE_AT,
DEVICE_ISA,
0,
lm75_init, lm75_close, NULL,
NULL, NULL, NULL,

View File

@@ -29,12 +29,13 @@
#include <86box/hwm.h>
#define LM78_SMBUS 0x10000
#define LM78_W83781D 0x20000
#define LM78_AS99127F_REV1 0x40000
#define LM78_AS99127F_REV2 0x80000
#define LM78_SMBUS 0x010000
#define LM78_W83781D 0x020000
#define LM78_AS99127F_REV1 0x040000
#define LM78_AS99127F_REV2 0x080000
#define LM78_W83782D 0x100000
#define LM78_AS99127F (LM78_AS99127F_REV1 | LM78_AS99127F_REV2) /* special mask covering both _REV1 and _REV2 */
#define LM78_WINBOND (LM78_W83781D | LM78_AS99127F) /* special mask covering all Winbond variants */
#define LM78_WINBOND (LM78_W83781D | LM78_AS99127F | LM78_W83782D) /* special mask covering all Winbond variants */
#define LM78_WINBOND_VENDOR_ID ((dev->local & LM78_AS99127F_REV1) ? 0x12c3 : 0x5ca3)
#define CLAMP(a, min, max) (((a) < (min)) ? (min) : (((a) > (max)) ? (max) : (a)))
@@ -48,6 +49,7 @@ typedef struct {
device_t *lm75[2];
uint8_t regs[256];
uint8_t regs_782d[2][16];
uint8_t addr_register;
uint8_t data_register;
@@ -100,25 +102,25 @@ lm78_remap(lm78_t *dev, uint8_t addr)
lm78_log("LM78: remapping to SMBus %02Xh\n", addr);
smbus_removehandler(dev->smbus_addr, 1,
lm78_smbus_read_byte, lm78_smbus_read_byte_cmd, lm78_smbus_read_word_cmd, NULL,
lm78_smbus_write_byte, lm78_smbus_write_byte_cmd, lm78_smbus_write_word_cmd, NULL,
dev);
lm78_smbus_read_byte, lm78_smbus_read_byte_cmd, lm78_smbus_read_word_cmd, NULL,
lm78_smbus_write_byte, lm78_smbus_write_byte_cmd, lm78_smbus_write_word_cmd, NULL,
dev);
if (addr < 0x80) smbus_sethandler(addr, 1,
lm78_smbus_read_byte, lm78_smbus_read_byte_cmd, lm78_smbus_read_word_cmd, NULL,
lm78_smbus_write_byte, lm78_smbus_write_byte_cmd, lm78_smbus_write_word_cmd, NULL,
dev);
lm78_smbus_read_byte, lm78_smbus_read_byte_cmd, lm78_smbus_read_word_cmd, NULL,
lm78_smbus_write_byte, lm78_smbus_write_byte_cmd, lm78_smbus_write_word_cmd, NULL,
dev);
dev->smbus_addr = addr;
if (dev->local & LM78_AS99127F) {
/* Store the main SMBus address on the LM75 devices to ensure reads/writes
to the AS99127F's proprietary registers are passed through to this side. */
for (uint8_t i = 0; i <= 1; i++) {
lm75 = device_get_priv(dev->lm75[i]);
if (lm75)
lm75->as99127f_smbus_addr = dev->smbus_addr;
}
/* Store the main SMBus address on the LM75 devices to ensure reads/writes
to the AS99127F's proprietary registers are passed through to this side. */
for (uint8_t i = 0; i <= 1; i++) {
lm75 = device_get_priv(dev->lm75[i]);
if (lm75)
lm75->as99127f_smbus_addr = dev->smbus_addr;
}
}
}
@@ -130,22 +132,23 @@ lm78_isa_read(uint16_t port, void *priv)
uint8_t ret = 0xff;
switch (port & 0x7) {
case 0x5:
ret = (dev->addr_register & 0x7f);
break;
case 0x6:
ret = lm78_read(dev, dev->addr_register, dev->active_bank);
case 0x5:
ret = (dev->addr_register & 0x7f);
break;
case 0x6:
ret = lm78_read(dev, dev->addr_register, dev->active_bank);
if ((dev->active_bank == 0) &&
((dev->addr_register == 0x41) || (dev->addr_register == 0x43) || (dev->addr_register == 0x45) || (dev->addr_register == 0x56) ||
((dev->addr_register >= 0x60) && (dev->addr_register < 0x7f)))) {
/* auto-increment registers */
dev->addr_register++;
}
break;
default:
lm78_log("LM78: Read from unknown ISA port %d\n", port & 0x7);
break;
if (((dev->active_bank == 0) &&
((dev->addr_register == 0x41) || (dev->addr_register == 0x43) || (dev->addr_register == 0x45) || (dev->addr_register == 0x56) ||
((dev->addr_register >= 0x60) && (dev->addr_register < 0x7f)))) ||
((dev->local & LM78_W83782D) && (dev->active_bank == 5) && (dev->addr_register >= 0x50) && (dev->addr_register < 0x58))) {
/* auto-increment registers */
dev->addr_register++;
}
break;
default:
lm78_log("LM78: Read from unknown ISA port %d\n", port & 0x7);
break;
}
return ret;
@@ -179,24 +182,50 @@ lm78_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv)
static uint8_t
lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank)
{
uint8_t ret = 0;
uint8_t ret = 0, masked_reg = reg;
lm75_t *lm75;
if (((reg & 0xf8) == 0x50) && (bank != 0)) {
/* LM75 registers */
lm75 = device_get_priv(dev->lm75[bank - 1]);
if (lm75)
ret = lm75_read(lm75, reg);
if (((reg & 0xf8) == 0x50) && ((bank == 1) || (bank == 2))) {
/* LM75 registers */
lm75 = device_get_priv(dev->lm75[bank - 1]);
if (lm75)
ret = lm75_read(lm75, reg);
} else if (((reg & 0xf8) == 0x50) && ((bank == 4) || (bank == 5) || (bank == 6))) {
/* W83782D additional registers */
if (dev->local & LM78_W83782D) {
if ((bank == 5) && ((reg == 0x50) || (reg == 0x51))) /* voltages */
ret = LM78_VOLTAGE_TO_REG(dev->values->voltages[7 + (reg & 1)]);
else if (bank < 6)
ret = dev->regs_782d[bank - 4][reg & 0x0f];
}
} else {
/* regular registers */
if ((reg == 0x4f) && (dev->local & LM78_WINBOND)) /* special case for two-byte vendor ID register */
ret = (dev->hbacs ? (LM78_WINBOND_VENDOR_ID >> 8) : LM78_WINBOND_VENDOR_ID);
else if ((reg >= 0x60) && (reg <= 0x7f)) /* read auto-increment value RAM registers from their non-auto-increment locations */
ret = dev->regs[reg & 0x3f];
else if ((reg >= 0x80) && (reg <= 0x92)) /* AS99127F mirrors [0x00:0x12] to [0x80:0x92] */
ret = dev->regs[reg & 0x7f];
else
ret = dev->regs[reg];
/* regular registers */
ret = dev->regs[reg];
if (reg >= 0x40)
masked_reg = reg & 0x3f; /* match both non-auto-increment and auto-increment locations */
if ((masked_reg >= 0x20) && (masked_reg <= 0x26)) /* voltages */
ret = LM78_VOLTAGE_TO_REG(dev->values->voltages[reg & 7]);
else if (masked_reg == 0x27) /* temperature */
ret = dev->values->temperatures[0];
else if ((masked_reg >= 0x28) && (masked_reg <= 0x2a)) /* fan speeds */
ret = LM78_RPM_TO_REG(dev->values->fans[reg & 3], 1 << ((dev->regs[((reg & 3) == 2) ? 0x4b : 0x47] >> ((reg & 3) ? 6 : 4)) & 0x3));
else if ((reg == 0x4f) && (dev->local & LM78_WINBOND)) /* two-byte vendor ID register */
ret = (dev->hbacs ? (LM78_WINBOND_VENDOR_ID >> 8) : LM78_WINBOND_VENDOR_ID);
else if ((reg >= 0x60) && (reg <= 0x7f)) /* read auto-increment value RAM registers from their non-auto-increment locations */
ret = dev->regs[reg & 0x3f];
else if (dev->local & LM78_AS99127F) { /* AS99127F mirrored registers */
masked_reg = reg & 0x7f;
if (masked_reg == 0x00) /* IN2 Low Limit */
ret = dev->regs[0x30];
else if ((masked_reg == 0x01) || (masked_reg == 0x04)) /* IN3 */
ret = LM78_VOLTAGE_TO_REG(dev->values->voltages[3]);
else if (masked_reg == 0x05) /* IN2 */
ret = LM78_VOLTAGE_TO_REG(dev->values->voltages[2]);
else if (masked_reg == 0x08) /* IN3 Low Limit */
ret = dev->regs[0x32];
else if ((reg >= 0x80) && (reg <= 0x92)) /* mirror [0x00:0x12] to [0x80:0x92] */
ret = dev->regs[masked_reg];
}
}
lm78_log("LM78: read(%02X, %d) = %02X\n", reg, bank, ret);
@@ -211,22 +240,23 @@ lm78_isa_write(uint16_t port, uint8_t val, void *priv)
lm78_t *dev = (lm78_t *) priv;
switch (port & 0x7) {
case 0x5:
dev->addr_register = (val & 0x7f);
break;
case 0x6:
lm78_write(dev, dev->addr_register, val, dev->active_bank);
case 0x5:
dev->addr_register = (val & 0x7f);
break;
case 0x6:
lm78_write(dev, dev->addr_register, val, dev->active_bank);
if ((dev->active_bank == 0) &&
((dev->addr_register == 0x41) || (dev->addr_register == 0x43) || (dev->addr_register == 0x45) || (dev->addr_register == 0x56) ||
((dev->addr_register >= 0x60) && (dev->addr_register < 0x7f)))) {
/* auto-increment registers */
dev->addr_register++;
}
break;
default:
lm78_log("LM78: Write %02X to unknown ISA port %d\n", val, port & 0x7);
break;
if (((dev->active_bank == 0) &&
((dev->addr_register == 0x41) || (dev->addr_register == 0x43) || (dev->addr_register == 0x45) || (dev->addr_register == 0x56) ||
((dev->addr_register >= 0x60) && (dev->addr_register < 0x7f)))) ||
((dev->local & LM78_W83782D) && (dev->active_bank == 5) && (dev->addr_register >= 0x50) && (dev->addr_register < 0x58))) {
/* auto-increment registers */
dev->addr_register++;
}
break;
default:
lm78_log("LM78: Write %02X to unknown ISA port %d\n", val, port & 0x7);
break;
}
}
@@ -262,90 +292,114 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank)
lm78_log("LM78: write(%02X, %d, %02X)\n", reg, bank, val);
if (((reg & 0xf8) == 0x50) && (bank != 0)) {
/* LM75 registers */
lm75 = device_get_priv(dev->lm75[bank - 1]);
if (lm75)
lm75_write(lm75, reg, val);
return 1;
if ((reg & 0xf8) == 0x50) {
if ((bank == 1) || (bank == 2)) {
/* LM75 registers */
lm75 = device_get_priv(dev->lm75[bank - 1]);
if (lm75)
lm75_write(lm75, reg, val);
return 1;
} else if (dev->local & LM78_W83782D) {
/* W83782D additional registers */
if (bank == 4) {
switch (reg) {
case 0x50: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5d: case 0x5e: case 0x5f:
/* read-only registers */
return 0;
}
dev->regs_782d[0][reg & 0x0f] = val;
return 1;
} else if (bank == 5) {
switch (reg) {
case 0x50: case 0x51: case 0x52: case 0x53: case 0x58: case 0x59: case 0x5a:
case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
/* read-only registers */
return 0;
}
dev->regs_782d[1][reg & 0x0f] = val;
return 1;
} else if (bank == 6) {
return 0;
}
}
}
/* regular registers */
switch (reg) {
case 0x41: case 0x42: case 0x4f: case 0x58:
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2a:
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a:
/* read-only registers */
return 0;
case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e:
/* Winbond-only registers */
if (!(dev->local & LM78_WINBOND))
return 0;
break;
case 0x41: case 0x42: case 0x4f: case 0x58:
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2a:
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a:
/* read-only registers */
return 0;
case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e:
/* Winbond-only registers */
if (!(dev->local & LM78_WINBOND))
return 0;
break;
}
if ((reg >= 0x60) && (reg <= 0x7f)) /* write auto-increment value RAM registers to their non-auto-increment locations */
dev->regs[reg & 0x3f] = val;
dev->regs[reg & 0x3f] = val;
else if ((reg >= 0x80) && (reg <= 0x92)) /* AS99127F mirrors [0x00:0x12] to [0x80:0x92] */
dev->regs[reg & 0x7f] = val;
dev->regs[reg & 0x7f] = val;
else
dev->regs[reg] = val;
dev->regs[reg] = val;
switch (reg) {
case 0x40:
if (val & 0x80) /* INITIALIZATION bit resets all registers except main SMBus address */
lm78_reset(dev, 1);
break;
case 0x47:
/* update FAN1/FAN2 values to match the new divisor */
dev->regs[0x28] = LM78_RPM_TO_REG(dev->values->fans[0], 1 << ((dev->regs[0x47] >> 4) & 0x3));
dev->regs[0x29] = LM78_RPM_TO_REG(dev->values->fans[1], 1 << ((dev->regs[0x47] >> 6) & 0x3));
break;
case 0x48:
/* set main SMBus address */
if (dev->local & LM78_SMBUS)
lm78_remap(dev, dev->regs[0x48] & 0x7f);
break;
case 0x49:
if (!(dev->local & LM78_WINBOND)) {
if (val & 0x20) /* Chip Reset bit (LM78 only) resets all registers */
lm78_reset(dev, 0);
else
dev->regs[0x49] = 0x40;
} else {
dev->regs[0x49] &= 0x01;
}
break;
case 0x4a:
/* set LM75 SMBus addresses (Winbond only) */
if (dev->local & LM78_SMBUS) {
for (uint8_t i = 0; i <= 1; i++) {
lm75 = device_get_priv(dev->lm75[i]);
if (!lm75)
continue;
if (dev->regs[0x4a] & (0x08 * (0x10 * i))) /* DIS_T2 and DIS_T3 bit disable those interfaces */
lm75_remap(lm75, 0x80);
else
lm75_remap(lm75, 0x48 + ((dev->regs[0x4a] >> (i * 4)) & 0x7));
}
}
break;
case 0x4b:
/* update FAN3 value to match the new divisor */
dev->regs[0x2a] = LM78_RPM_TO_REG(dev->values->fans[2], 1 << ((dev->regs[0x4b] >> 6) & 0x3));
break;
case 0x4e:
dev->hbacs = (dev->regs[0x4e] & 0x80);
/* BANKSEL[0:2] is a bitfield according to the datasheet, but not in reality */
dev->active_bank = (dev->regs[0x4e] & 0x07);
break;
case 0x87:
/* fixes AS99127F boards hanging after BIOS save & exit, probably a reset register */
if ((dev->local & LM78_AS99127F) && (val == 0x01)) {
lm78_log("LM78: Reset requested through AS99127F\n");
resetx86();
}
break;
case 0x40:
if (val & 0x80) /* INITIALIZATION bit resets all registers except main SMBus address */
lm78_reset(dev, 1);
break;
case 0x48:
/* set main SMBus address */
if (dev->local & LM78_SMBUS)
lm78_remap(dev, dev->regs[0x48] & 0x7f);
break;
case 0x49:
if (!(dev->local & LM78_WINBOND)) {
if (val & 0x20) /* Chip Reset bit (LM78 only) resets all registers */
lm78_reset(dev, 0);
else
dev->regs[0x49] = 0x40;
} else {
dev->regs[0x49] &= 0x01;
}
break;
case 0x4a:
/* set LM75 SMBus addresses (Winbond only) */
if (dev->local & LM78_SMBUS) {
for (uint8_t i = 0; i <= 1; i++) {
lm75 = device_get_priv(dev->lm75[i]);
if (!lm75)
continue;
if (dev->regs[0x4a] & (0x08 * (0x10 * i))) /* DIS_T2 and DIS_T3 bit disable those interfaces */
lm75_remap(lm75, 0x80);
else
lm75_remap(lm75, 0x48 + ((dev->regs[0x4a] >> (i * 4)) & 0x7));
}
}
break;
case 0x4e:
dev->hbacs = (dev->regs[0x4e] & 0x80);
/* BANKSEL[0:2] is a bitfield according to the datasheet, but not in reality */
dev->active_bank = (dev->regs[0x4e] & 0x07);
break;
case 0x87:
/* AS99127F boards perform a soft reset through this register */
if ((dev->local & LM78_AS99127F) && (val == 0x01)) {
lm78_log("LM78: Reset requested through AS99127F\n");
resetx86();
}
break;
}
return 1;
@@ -358,69 +412,65 @@ lm78_reset(lm78_t *dev, uint8_t initialization)
memset(dev->regs, 0, 256);
memset(dev->regs + 0xc0, 0xff, 32); /* C0-DF are 0xFF at least on the AS99127F */
uint8_t i;
for (i = 0; i <= 6; i++)
dev->regs[0x20 + i] = LM78_VOLTAGE_TO_REG(dev->values->voltages[i]);
dev->regs[0x27] = dev->values->temperatures[0];
for (i = 0; i <= 2; i++)
dev->regs[0x28 + i] = LM78_RPM_TO_REG(dev->values->fans[i], 2);
dev->regs[0x40] = 0x08;
dev->regs[0x46] = 0x40;
dev->regs[0x47] = 0x50;
if (dev->local & LM78_SMBUS) {
if (!initialization) /* don't reset main SMBus address if the reset was triggered by the INITIALIZATION bit */
dev->smbus_addr = 0x2d;
dev->regs[0x48] = dev->smbus_addr;
if (dev->local & LM78_WINBOND)
dev->regs[0x4a] = 0x01;
if (!initialization) /* don't reset main SMBus address if the reset was triggered by the INITIALIZATION bit */
dev->smbus_addr = 0x2d;
dev->regs[0x48] = dev->smbus_addr;
if (dev->local & LM78_WINBOND)
dev->regs[0x4a] = 0x01;
} else {
dev->regs[0x48] = 0x00;
if (dev->local & LM78_WINBOND)
dev->regs[0x4a] = 0x88;
dev->regs[0x48] = 0x00;
if (dev->local & LM78_WINBOND)
dev->regs[0x4a] = 0x88;
}
if (dev->local & LM78_WINBOND) {
dev->regs[0x49] = 0x02;
dev->regs[0x4b] = 0x44;
dev->regs[0x4c] = 0x01;
dev->regs[0x4d] = 0x15;
dev->regs[0x4e] = 0x80;
dev->hbacs = (dev->regs[0x4e] & 0x80);
dev->regs[0x4f] = (LM78_WINBOND_VENDOR_ID >> 8);
dev->regs[0x57] = 0x80;
dev->regs[0x49] = 0x02;
dev->regs[0x4b] = 0x44;
dev->regs[0x4c] = 0x01;
dev->regs[0x4d] = 0x15;
dev->regs[0x4e] = 0x80;
dev->hbacs = (dev->regs[0x4e] & 0x80);
dev->regs[0x4f] = (LM78_WINBOND_VENDOR_ID >> 8);
dev->regs[0x57] = 0x80;
/* Initialize proprietary registers on the AS99127F. The BIOS accesses some
of these on boot through read_byte_cmd on the TEMP2 address, hanging on
POST code C1 if they're defaulted to 0. There's no documentation on what
these are for. The following values were dumped from a live, initialized
AS99127F Rev. 2 on a P4B motherboard, and they seem to work well enough. */
if (dev->local & LM78_AS99127F) {
/* 0x00 appears to mirror IN2 Low Limit */
dev->regs[0x01] = dev->regs[0x23]; /* appears to mirror IN3 */
dev->regs[0x02] = LM78_VOLTAGE_TO_REG(2800); /* appears to be a "maximum VCORE" of some kind; must read 2.8V on P3 boards */
dev->regs[0x03] = 0x60;
dev->regs[0x04] = dev->regs[0x23]; /* appears to mirror IN3 */
dev->regs[0x05] = dev->regs[0x22]; /* appears to mirror IN2 */
dev->regs[0x07] = 0xcd;
/* 0x08 appears to mirror IN3 Low Limit */
dev->regs[0x09] = dev->regs[0x0f] = dev->regs[0x11] = 0xf8; /* three instances of */
dev->regs[0x0a] = dev->regs[0x10] = dev->regs[0x12] = 0xa5; /* the same word */
dev->regs[0x0b] = 0xac;
dev->regs[0x0c] = 0x8c;
dev->regs[0x0d] = 0x68;
dev->regs[0x0e] = 0x54;
/* Initialize proprietary registers on the AS99127F. The BIOS accesses some
of these on boot through read_byte_cmd on the TEMP2 address, hanging on
POST code C1 if they're defaulted to 0. There's no documentation on what
these are for. The following values were dumped from a live, initialized
AS99127F Rev. 2 on a P4B motherboard, and they seem to work well enough. */
if (dev->local & LM78_AS99127F) {
/* 0x00 appears to mirror IN2 Low Limit */
/* 0x01 appears to mirror IN3 */
dev->regs[0x02] = LM78_VOLTAGE_TO_REG(2800); /* appears to be a "maximum VCORE" of some kind; must read 2.8V on P3 boards */
dev->regs[0x03] = 0x60;
/* 0x04 appears to mirror IN3 */
/* 0x05 appears to mirror IN2 */
dev->regs[0x07] = 0xcd;
/* 0x08 appears to mirror IN3 Low Limit */
dev->regs[0x09] = dev->regs[0x0f] = dev->regs[0x11] = 0xf8; /* three instances of */
dev->regs[0x0a] = dev->regs[0x10] = dev->regs[0x12] = 0xa5; /* the same word */
dev->regs[0x0b] = 0xac;
dev->regs[0x0c] = 0x8c;
dev->regs[0x0d] = 0x68;
dev->regs[0x0e] = 0x54;
dev->regs[0x53] = dev->regs[0x54] = dev->regs[0x55] = 0xff;
dev->regs[0x58] = 0x31;
dev->regs[0x59] = dev->regs[0x5a] = 0x8f;
dev->regs[0x5c] = 0xe0;
dev->regs[0x5d] = 0x48;
dev->regs[0x5e] = 0xe2;
dev->regs[0x5f] = 0x3f;
} else {
dev->regs[0x58] = 0x10;
}
dev->regs[0x53] = dev->regs[0x54] = dev->regs[0x55] = 0xff;
dev->regs[0x58] = 0x31;
dev->regs[0x59] = dev->regs[0x5a] = 0x8f;
dev->regs[0x5c] = 0xe0;
dev->regs[0x5d] = 0x48;
dev->regs[0x5e] = 0xe2;
dev->regs[0x5f] = 0x3f;
} else if (dev->local & LM78_W83781D) {
dev->regs[0x58] = 0x10;
} else if (dev->local & LM78_W83782D) {
dev->regs[0x58] = 0x30;
}
} else {
dev->regs[0x49] = 0x40;
dev->regs[0x49] = 0x40;
}
lm78_remap(dev, dev->smbus_addr);
@@ -434,7 +484,7 @@ lm78_close(void *priv)
uint16_t isa_io = (dev->local & 0xffff);
if (isa_io)
io_removehandler(isa_io, 8, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev);
io_removehandler(isa_io, 8, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev);
free(dev);
}
@@ -447,27 +497,61 @@ lm78_init(const device_t *info)
memset(dev, 0, sizeof(lm78_t));
dev->local = info->local;
dev->values = hwm_get_values();
/* initialize secondary/tertiary LM75 sensors on Winbond */
/* Set default values. */
hwm_values_t defaults = {
{ /* fan speeds */
3000, /* usually Chassis, sometimes CPU */
3000, /* usually CPU, sometimes Chassis */
3000 /* usually PSU, sometimes Chassis */
}, { /* temperatures */
30, /* usually Board, sometimes Chassis */
30, /* Winbond only: usually CPU, sometimes Probe */
30 /* Winbond only: usually CPU when not the one above */
}, { /* voltages */
hwm_get_vcore(), /* Vcore */
0, /* sometimes Vtt, Vio or second CPU */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
12000 * (604.0 / 2100.0), /* -12V (Rf/Rin negative voltage formula from the W83781D datasheet) */
5000 * (604.0 / 909.0), /* -5V (Rf/Rin negative voltage formula from the W83781D datasheet) */
RESISTOR_DIVIDER(5000, 51, 75), /* W83782D only: +5VSB (5.1K/7.5K divider suggested in the datasheet) */
3000 /* W83782D only: VBAT */
}
};
/* Set per-chip defaults. */
if (dev->local & LM78_AS99127F) {
defaults.voltages[5] = 12000 * (604.0 / 2400.0); /* different -12V Rin value for AS99127F (bruteforced) */
} else if (dev->local & LM78_W83782D) {
/* different negative voltage formula for W83782D (from the datasheet) */
defaults.voltages[5] = ((3600 + 12000) * (232.0 / (232.0 + 56.0))) - 12000;
defaults.voltages[6] = ((3600 + 5000) * (120.0 / (120.0 + 56.0))) - 5000;
}
hwm_values = defaults;
dev->values = &hwm_values;
/* Initialize secondary/tertiary LM75 sensors on Winbond. */
for (uint8_t i = 0; i <= 1; i++) {
if (dev->local & LM78_WINBOND) {
dev->lm75[i] = (device_t *) malloc(sizeof(device_t));
memcpy(dev->lm75[i], &lm75_w83781d_device, sizeof(device_t));
dev->lm75[i]->local = ((i + 1) << 8);
if (dev->local & LM78_SMBUS)
dev->lm75[i]->local |= (0x48 + i);
device_add(dev->lm75[i]);
} else {
dev->lm75[i] = NULL;
}
if (dev->local & LM78_WINBOND) {
dev->lm75[i] = (device_t *) malloc(sizeof(device_t));
memcpy(dev->lm75[i], &lm75_w83781d_device, sizeof(device_t));
dev->lm75[i]->local = ((i + 1) << 8);
if (dev->local & LM78_SMBUS)
dev->lm75[i]->local |= (0x48 + i);
device_add(dev->lm75[i]);
} else {
dev->lm75[i] = NULL;
}
}
lm78_reset(dev, 0);
uint16_t isa_io = (dev->local & 0xffff);
if (isa_io)
io_sethandler(isa_io, 8, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev);
io_sethandler(isa_io, 8, lm78_isa_read, NULL, NULL, lm78_isa_write, NULL, NULL, dev);
return dev;
}
@@ -495,8 +579,8 @@ const device_t w83781d_device = {
};
/* The ASUS AS99127F is a customized W83781D with no ISA interface (SMBus only),
added proprietary registers and different chip/vendor IDs. */
/* The ASUS AS99127F is a customized W83781D with no ISA interface (SMBus
only), added proprietary registers and different chip/vendor IDs. */
const device_t as99127f_device = {
"ASUS AS99127F Rev. 1 Hardware Monitor",
DEVICE_ISA,
@@ -510,9 +594,20 @@ const device_t as99127f_device = {
/* Rev. 2 changes the vendor ID back to Winbond's and brings some other changes. */
const device_t as99127f_rev2_device = {
"ASUS AS99127F Rev. 2 Hardware Monitor",
DEVICE_AT,
DEVICE_ISA,
LM78_SMBUS | LM78_AS99127F_REV2,
lm78_init, lm78_close, NULL,
NULL, NULL, NULL,
NULL
};
/* Winbond W83782D on ISA and SMBus. */
const device_t w83782d_device = {
"Winbond W83782D Hardware Monitor",
DEVICE_ISA,
0x290 | LM78_SMBUS | LM78_W83782D,
lm78_init, lm78_close, NULL,
NULL, NULL, NULL,
NULL
};

View File

@@ -24,16 +24,15 @@
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include "cpu.h"
#include <86box/smbus.h>
#include <86box/hwm.h>
#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)
/* Temperature formula from source comments in 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_VOLTAGE_TO_REG(v) ((v) >> 4)
#define VT82C686_VOLTAGE_TO_REG(v, f) CLAMP((((v) * (2.628 / (f))) - 120.5) / 25, 0, 255)
typedef struct {
@@ -67,10 +66,10 @@ vt82c686_write(uint16_t port, uint8_t val, void *priv)
return;
switch (reg) {
case 0x40:
if (val & 0x80)
vt82c686_reset(dev, 1);
break;
case 0x40:
if (val & 0x80)
vt82c686_reset(dev, 1);
break;
case 0x47:
val &= 0xf0;
@@ -92,19 +91,19 @@ vt82c686_hwm_write(uint8_t addr, uint8_t val, void *priv)
vt82c686_t *dev = (vt82c686_t *) priv;
if (dev->io_base)
io_removehandler(dev->io_base, 0x0050,
io_removehandler(dev->io_base, 0x0050,
vt82c686_read, NULL, NULL, vt82c686_write, NULL, NULL, dev);
switch (addr) {
case 0x70:
dev->io_base &= 0xff00;
dev->io_base |= val & 0x80;
break;
case 0x70:
dev->io_base &= 0xff00;
dev->io_base |= val & 0x80;
break;
case 0x71:
dev->io_base &= 0x00ff;
dev->io_base |= val << 8;
break;
case 0x71:
dev->io_base &= 0x00ff;
dev->io_base |= val << 8;
break;
case 0x74:
dev->enable = val & 0x01;
@@ -112,7 +111,7 @@ vt82c686_hwm_write(uint8_t addr, uint8_t val, void *priv)
}
if (dev->enable && dev->io_base)
io_sethandler(dev->io_base, 0x0050,
io_sethandler(dev->io_base, 0x0050,
vt82c686_read, NULL, NULL, vt82c686_write, NULL, NULL, dev);
}
@@ -126,11 +125,11 @@ vt82c686_reset(vt82c686_t *dev, uint8_t initialization)
dev->regs[0x20] = VT82C686_TEMP_TO_REG(dev->values->temperatures[0]);
dev->regs[0x21] = VT82C686_TEMP_TO_REG(dev->values->temperatures[1]);
dev->regs[0x22] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[0]);
dev->regs[0x23] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[1]);
dev->regs[0x24] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[2]);
dev->regs[0x25] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[3]);
dev->regs[0x26] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[4]);
dev->regs[0x22] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[0], 1.25);
dev->regs[0x23] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[1], 1.25);
dev->regs[0x24] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[2], 1.67);
dev->regs[0x25] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[3], 2.6);
dev->regs[0x26] = VT82C686_VOLTAGE_TO_REG(dev->values->voltages[4], 6.3);
dev->regs[0x29] = VT82C686_RPM_TO_REG(dev->values->fans[0], 2);
dev->regs[0x2a] = VT82C686_RPM_TO_REG(dev->values->fans[1], 2);
@@ -162,7 +161,26 @@ vt82c686_init(const device_t *info)
vt82c686_t *dev = (vt82c686_t *) malloc(sizeof(vt82c686_t));
memset(dev, 0, sizeof(vt82c686_t));
dev->values = hwm_get_values();
/* Set default values. Since this hardware monitor has a complex voltage factor system,
the values struct contains voltage values *before* applying their respective factors. */
hwm_values_t defaults = {
{ /* fan speeds */
3000, /* CPU */
3000 /* Chassis */
}, { /* temperatures */
30, /* CPU */
30, /* System */
0 /* unused */
}, { /* voltages */
hwm_get_vcore(), /* Vcore */
2500, /* 2.5V */
3300, /* 3.3V */
5000, /* 5V */
12000 /* 12V */
}
};
hwm_values = defaults;
dev->values = &hwm_values;
vt82c686_reset(dev, 0);

View File

@@ -66,16 +66,16 @@ static void
postcard_setui(void)
{
if (!postcard_written)
sprintf(postcard_str, "POST: -- --");
sprintf(postcard_str, "POST: -- --");
else if (postcard_written == 1)
sprintf(postcard_str, "POST: %02X --", postcard_code);
sprintf(postcard_str, "POST: %02X --", postcard_code);
else
sprintf(postcard_str, "POST: %02X %02X", postcard_code, postcard_prev_code);
sprintf(postcard_str, "POST: %02X %02X", postcard_code, postcard_prev_code);
ui_sb_bugui(postcard_str);
if (postcard_do_log) {
/* log same string sent to the UI */
/* log same string sent to the UI */
postcard_log("[%04X:%08X] %s\n", CS, cpu_state.pc, postcard_str);
}
}
@@ -95,12 +95,12 @@ static void
postcard_write(uint16_t port, uint8_t val, void *priv)
{
if (postcard_written && val == postcard_code)
return;
return;
postcard_prev_code = postcard_code;
postcard_code = val;
if (postcard_written < 2)
postcard_written++;
postcard_written++;
postcard_setui();
}
@@ -112,13 +112,15 @@ postcard_init(const device_t *info)
postcard_reset();
if (machines[machine].flags & MACHINE_MCA)
postcard_port = 0x680; /* MCA machines */
postcard_port = 0x680; /* MCA machines */
else if (strstr(machines[machine].name, " PS/2 ") || strstr(machines[machine].name, " PS/1 "))
postcard_port = 0x190; /* ISA PS/2 machines */
postcard_port = 0x190; /* ISA PS/2 machines */
else if (strstr(machines[machine].name, " IBM XT "))
postcard_port = 0x60; /* IBM XT */
else if (strstr(machines[machine].name, " Compaq ") && !(machines[machine].flags & MACHINE_PCI))
postcard_port = 0x84; /* ISA Compaq machines */
postcard_port = 0x84; /* ISA Compaq machines */
else
postcard_port = 0x80; /* AT and clone machines */
postcard_port = 0x80; /* AT and clone machines */
postcard_log("POST card initializing on port %04Xh\n", postcard_port);
if (postcard_port) io_sethandler(postcard_port, 1,

View File

@@ -2160,6 +2160,13 @@ fdc_set_irq(fdc_t *fdc, int irq)
}
void
fdc_set_dma_ch(fdc_t *fdc, int dma_ch)
{
fdc->dma_ch = dma_ch;
}
void
fdc_set_base(fdc_t *fdc, int base)
{

View File

@@ -155,6 +155,7 @@ extern int fdc_is_verify(fdc_t *fdc);
extern void fdc_overrun(fdc_t *fdc);
extern void fdc_set_base(fdc_t *fdc, int base);
extern void fdc_set_irq(fdc_t *fdc, int irq);
extern void fdc_set_dma_ch(fdc_t *fdc, int dma_ch);
extern int fdc_getdata(fdc_t *fdc, int last);
extern int fdc_data(fdc_t *fdc, uint8_t data);

View File

@@ -16,15 +16,16 @@
*/
#ifndef EMU_HWM_H
# define EMU_HWM_H
# include <stdint.h>
#define RESISTOR_DIVIDER(v, r1, r2) (((v) * (r2)) / ((r1) + (r2)))
typedef struct _hwm_values_ {
typedef struct {
uint16_t fans[4];
uint8_t temperatures[4];
uint16_t voltages[8];
uint16_t voltages[9];
} hwm_values_t;
typedef struct {
@@ -40,8 +41,7 @@ typedef struct {
} lm75_t;
extern void hwm_set_values(hwm_values_t new_values);
extern hwm_values_t* hwm_get_values();
extern uint16_t hwm_get_vcore();
extern void lm75_remap(lm75_t *dev, uint8_t addr);
extern uint8_t lm75_read(lm75_t *dev, uint8_t reg);
@@ -50,6 +50,9 @@ extern uint8_t lm75_write(lm75_t *dev, uint8_t reg, uint8_t val);
extern void vt82c686_hwm_write(uint8_t addr, uint8_t val, void *priv);
/* Refer to specific hardware monitor implementations for the meaning of hwm_values. */
extern hwm_values_t hwm_values;
extern const device_t lm75_1_4a_device;
extern const device_t lm75_w83781d_device;
@@ -57,6 +60,7 @@ extern const device_t lm78_device;
extern const device_t w83781d_device;
extern const device_t as99127f_device;
extern const device_t as99127f_rev2_device;
extern const device_t w83782d_device;
extern const device_t gl518sm_2c_device;
extern const device_t gl518sm_2d_device;

View File

@@ -918,26 +918,10 @@ machine_at_itoxstar_init(const machine_t *model)
device_add(&keyboard_ps2_ami_pci_device);
device_add(&stpc_client_device);
device_add(&sst_flash_29ee020_device);
hwm_values_t machine_hwm = {
{ /* fan speeds (incorrect divisor for some reason) */
3000, /* Chassis */
3000 /* CPU */
}, { /* temperatures */
30, /* Chassis */
30 /* CPU */
}, { /* voltages */
0, /* unused */
0, /* unused */
3300, /* Vio */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
hwm_set_values(machine_hwm);
device_add(&w83781d_device);
device_add(&w83781d_device); /* fans: Chassis, CPU, unused; temperatures: Chassis, CPU, unused */
hwm_values.fans[2] = 0; /* unused */
hwm_values.temperatures[2] = 0; /* unused */
hwm_values.voltages[0] = 0; /* Vcore unused */
return ret;
}

View File

@@ -81,26 +81,9 @@ machine_at_kn97_init(const machine_t *model)
device_add(&keyboard_ps2_pci_device);
device_add(&w83877f_device);
device_add(&intel_flash_bxt_device);
hwm_values_t machine_hwm = {
{ /* fan speeds (incorrect divisor for some reason) */
6000, /* Chassis */
6000, /* CPU */
6000 /* Power */
}, { /* temperatures */
30 /* MB */
}, { /* voltages */
2800, /* VCORE (2.8V by default) */
0, /* unused */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
hwm_set_values(machine_hwm);
device_add(&lm78_device);
device_add(&lm78_device); /* fans: Chassis, CPU, Power; temperature: MB */
for (uint8_t i = 0; i < 3; i++)
hwm_values.fans[i] *= 2; /* BIOS reports fans with the wrong divisor for some reason */
return ret;
}
@@ -159,27 +142,8 @@ machine_at_spitfire_init(const machine_t *model)
device_add(&keyboard_ps2_pci_device);
device_add(&fdc37c935_device);
device_add(&intel_flash_bxt_device);
spd_register(SPD_TYPE_SDRAM, 0xF, 256);
hwm_values_t machine_hwm = {
{ /* fan speeds (incorrect divisor for some reason) */
6000, /* Chassis */
6000, /* CPU */
6000 /* Power */
}, { /* temperatures */
30 /* MB */
}, { /* voltages */
2800, /* VCORE (2.8V by default) */
0, /* unused */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
hwm_set_values(machine_hwm);
device_add(&lm78_device);
spd_register(SPD_TYPE_SDRAM, 0xF, 256);
device_add(&lm78_device); /* no reporting in BIOS */
return ret;
}
@@ -210,30 +174,9 @@ machine_at_p6i440e2_init(const machine_t *model)
device_add(&w83977tf_device);
device_add(&sst_flash_29ee010_device);
spd_register(SPD_TYPE_SDRAM, 0x03, 256);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* Chassis */
3000, /* CPU */
3000 /* Power */
}, { /* temperatures */
30, /* MB */
0, /* unused */
27 /* CPU */
}, { /* voltages */
2050, /* VCORE (2.05V by default) */
0, /* unused */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2)
machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */
hwm_set_values(machine_hwm);
device_add(&w83781d_device);
device_add(&w83781d_device); /* fans: CPU, CHS, PS; temperatures: unused, CPU, System */
hwm_values.temperatures[0] = 0; /* unused */
hwm_values.voltages[1] = 1500; /* CPUVTT */
return ret;
}
@@ -268,30 +211,9 @@ machine_at_p2bls_init(const machine_t *model)
device_add(&w83977ef_device);
device_add(&sst_flash_39sf020_device);
spd_register(SPD_TYPE_SDRAM, 0xF, 256);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* Chassis */
3000, /* CPU */
3000 /* Power */
}, { /* temperatures */
30, /* MB */
0, /* unused */
27 /* CPU */
}, { /* voltages */
2050, /* VCORE (2.05V by default) */
0, /* unused */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2)
machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */
hwm_set_values(machine_hwm);
device_add(&w83781d_device);
device_add(&w83781d_device); /* fans: Chassis, CPU, Power; temperatures: MB, unused, CPU */
hwm_values.temperatures[1] = 0; /* unused */
hwm_values.temperatures[2] -= 3; /* CPU offset */
return ret;
}
@@ -326,30 +248,8 @@ machine_at_p3bf_init(const machine_t *model)
device_add(&w83977ef_device);
device_add(&sst_flash_39sf020_device);
spd_register(SPD_TYPE_SDRAM, 0xF, 256);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* Chassis */
3000, /* CPU */
3000 /* Power */
}, { /* temperatures */
30, /* MB */
30, /* JTPWR */
30 /* CPU */
}, { /* voltages */
2050, /* VCORE (2.05V by default) */
0, /* unused */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 3, 1), /* +12V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 59, 20), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2)
machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */
hwm_set_values(machine_hwm);
device_add(&as99127f_device);
device_add(&as99127f_device); /* fans: Chassis, CPU, Power; temperatures: MB, JTPWR, CPU */
hwm_values.voltages[4] = hwm_values.voltages[5]; /* +12V reading not in line with other boards; appears to be close to the -12V reading */
return ret;
}
@@ -418,23 +318,7 @@ machine_at_ax6bc_init(const machine_t *model)
device_add(&w83977tf_device);
device_add(&sst_flash_29ee020_device);
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* System */
3000 /* CPU */
}, { /* temperatures */
30 /* CPU */
}, { /* voltages */
2050, /* VCORE (2.05V by default) */
RESISTOR_DIVIDER(12000, 150, 47), /* +12V (15K/4.7K divider suggested in the GL518SM datasheet) */
3300 /* +3.3V */
}
};
if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2)
machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */
hwm_set_values(machine_hwm);
device_add(&gl518sm_2d_device);
device_add(&gl518sm_2d_device); /* fans: System, CPU; temperature: CPU; no reporting in BIOS */
return ret;
}
@@ -502,30 +386,11 @@ machine_at_p6sba_init(const machine_t *model)
device_add(&keyboard_ps2_ami_pci_device);
device_add(&intel_flash_bxt_device);
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* CPU1 */
0, /* CPU2 */
3000 /* Thermal Control */
}, { /* temperatures */
0, /* unused */
30, /* CPU1 */
0 /* unused (CPU2?) */
}, { /* voltages */
2050, /* CPU1 (2.05V by default) */
0, /* CPU2 */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2)
machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */
hwm_set_values(machine_hwm);
device_add(&w83781d_device);
device_add(&w83781d_device); /* fans: CPU1, CPU2, Thermal Control; temperatures: unused, CPU1, CPU2? */
hwm_values.fans[1] = 0; /* no CPU2 fan */
hwm_values.temperatures[0] = 0; /* unused */
hwm_values.temperatures[2] = 0; /* CPU2? */
/* no CPU2 voltage */
return ret;
}

View File

@@ -67,30 +67,12 @@ machine_at_6gxu_init(const machine_t *model)
device_add(&w83977ef_device);
device_add(&sst_flash_39sf020_device);
spd_register(SPD_TYPE_SDRAM, 0xF, 512);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* Chassis */
3000, /* CPU */
3000 /* Power */
}, { /* temperatures */
30, /* MB */
0, /* unused */
27 /* CPU */
}, { /* voltages */
2050, /* VCORE (2.05V by default) */
0, /* unused */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2)
machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */
hwm_set_values(machine_hwm);
device_add(&w83781d_device);
device_add(&w83782d_device); /* fans: ???, ???, System; temperatures: System, CPU, unused */
hwm_values.fans[0] = 2000;
hwm_values.fans[1] = 2500;
hwm_values.fans[2] = 3000;
hwm_values.temperatures[2] = 0; /* unused */
hwm_values.voltages[1] = 1500; /* VGTL */
return ret;
}
@@ -125,31 +107,11 @@ machine_at_s2dge_init(const machine_t *model)
device_add(&w83977tf_device);
device_add(&intel_flash_bxt_device);
spd_register(SPD_TYPE_SDRAM, 0xF, 512);
device_add(&w83781d_device); /* fans: CPU1, CPU2, Thermal Control; temperatures: unused, CPU1, CPU2? */
hwm_values.fans[1] = 0; /* no CPU2 fan */
hwm_values.temperatures[0] = 0; /* unused */
hwm_values.temperatures[2] = 0; /* CPU2? */
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* CPU1 */
0, /* CPU2 */
3000 /* Thermal Control */
}, { /* temperatures */
0, /* unused */
30, /* CPU1 */
20 /* unused (CPU2?) */
}, { /* voltages */
2050, /* CPU1 (2.05V by default) */
0, /* CPU2 */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2)
machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */
hwm_set_values(machine_hwm);
device_add(&w83781d_device);
return ret;
}
@@ -183,30 +145,9 @@ machine_at_fw6400gx_init(const machine_t *model)
device_add(&pc87309_15c_device);
device_add(&sst_flash_29ee020_device);
spd_register(SPD_TYPE_SDRAM, 0xF, 512);
device_add(&w83781d_device); /* fans: Chassis, Power, CPU; temperatures: System, CPU, unused */
hwm_values.temperatures[3] = 0; /* unused */
hwm_values.voltages[1] = 1500; /* Vtt */
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* Chassis */
3000, /* Power */
3000 /* CPU */
}, { /* temperatures */
30, /* System */
30, /* CPU */
0 /* unused */
}, { /* voltages */
2050, /* Vcore (2.05V by default) */
1500, /* Vtt */
3300, /* Vio */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUM2)
machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Klamath */
hwm_set_values(machine_hwm);
device_add(&w83781d_device);
return ret;
}

View File

@@ -64,28 +64,9 @@ machine_at_s370slm_init(const machine_t *model)
device_add(&keyboard_ps2_ami_pci_device);
device_add(&intel_flash_bxt_device);
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* CPU */
3000, /* Fan 2 */
3000 /* Chassis */
}, { /* temperatures */
0, /* unused */
30, /* CPU */
0 /* unused */
}, { /* voltages */
2050, /* CPU1 (2.05V by default) */
0, /* unused */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
hwm_set_values(machine_hwm);
device_add(&w83781d_device);
device_add(&w83781d_device); /* fans: CPU, Fan 2, Chassis; temperatures: unused, CPU, unused */
hwm_values.temperatures[0] = 0; /* unused */
hwm_values.temperatures[2] = 0; /* unused */
return ret;
}
@@ -117,32 +98,10 @@ machine_at_cubx_init(const machine_t *model)
device_add(&i440bx_device);
device_add(&piix4e_device);
device_add(&keyboard_ps2_ami_pci_device);
// device_add(&keyboard_ps2_pci_device);
device_add(&w83977ef_device);
device_add(&sst_flash_39sf020_device);
spd_register(SPD_TYPE_SDRAM, 0xF, 256);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* Chassis */
3000, /* CPU */
3000 /* Power */
}, { /* temperatures */
30, /* MB */
30, /* JTPWR */
30 /* CPU */
}, { /* voltages */
2050, /* VCORE (2.05V by default) */
0, /* unused */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 59, 20), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
hwm_set_values(machine_hwm);
device_add(&as99127f_device);
device_add(&as99127f_device); /* fans: Chassis, CPU, Power; temperatures: MB, JTPWR, CPU */
return ret;
}
@@ -366,27 +325,6 @@ machine_at_6via85x_init(const machine_t *model)
device_add(&keyboard_ps2_ami_pci_device);
device_add(&sst_flash_39sf020_device);
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* Chassis */
3000, /* CPU */
3000 /* Power */
}, { /* temperatures */
30, /* MB */
30, /* JTPWR */
30 /* CPU */
}, { /* voltages */
2050, /* VCORE (2.05V by default) */
0, /* unused */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 59, 20), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
hwm_set_values(machine_hwm);
device_add(&via_vt82c686_hwm_device);
return ret;
@@ -419,27 +357,6 @@ machine_at_603tcf_init(const machine_t *model)
device_add(&keyboard_ps2_ami_pci_device);
device_add(&sst_flash_39sf020_device);
spd_register(SPD_TYPE_SDRAM, 0x3, 256);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* Chassis */
3000, /* CPU */
3000 /* Power */
}, { /* temperatures */
30, /* MB */
30, /* JTPWR */
30 /* CPU */
}, { /* voltages */
2050, /* VCORE (2.05V by default) */
0, /* unused */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 59, 20), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
hwm_set_values(machine_hwm);
device_add(&via_vt82c686_hwm_device);
return ret;

View File

@@ -817,41 +817,11 @@ machine_at_nupro592_init(const machine_t *model)
device_add(&w83977ef_device);
device_add(&intel_flash_bxt_device);
spd_register(SPD_TYPE_SDRAM, 0x3, 128);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* Chassis */
3000, /* CPU */
3000, /* Power */
0
}, { /* temperatures */
30, /* MB */
0, /* unused */
27, /* CPU */
0
}, { /* voltages */
3300, /* VCORE (3.3V by default) */
0, /* unused */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2), /* -5V (divider values bruteforced) */
0
}
};
/* Pentium, Pentium OverDrive MMX, Pentium Mobile MMX: 3.3V (real Pentium Mobile MMX is 2.45V).
Pentium MMX: 2.8 V.
AMD K6 Model 6: 2.9 V for 166/200, 3.2 V for 233.
AMD K6 Model 7: 2.2 V. */
if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMMMX)
machine_hwm.voltages[0] = 2800; /* set higher VCORE (2.8V) for Pentium MMX */
else if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_K6)
machine_hwm.voltages[0] = 2200; /* set higher VCORE (2.8V) for Pentium MMX */
else if (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_K6_2)
machine_hwm.voltages[0] = 2200; /* set higher VCORE (2.8V) for Pentium MMX */
hwm_set_values(machine_hwm);
device_add(&w83781d_device);
device_add(&w83781d_device); /* fans: CPU1, unused, unused; temperatures: System, CPU1, unused */
hwm_values.temperatures[2] = 0; /* unused */
hwm_values.fans[1] = 0; /* unused */
hwm_values.fans[2] = 0; /* unused */
/* -5V is not reported by the BIOS, but leave it set */
return ret;
}
@@ -884,41 +854,13 @@ machine_at_tx97_init(const machine_t *model)
device_add(&w83877tf_acorp_device);
device_add(&intel_flash_bxt_device);
spd_register(SPD_TYPE_SDRAM, 0x3, 128);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* Chassis */
3000, /* CPU */
3000 /* Power */
}, { /* temperatures */
30, /* MB */
0, /* unused */
8 /* CPU */
}, { /* voltages */
3300, /* VCORE (3.3V by default) */
0, /* unused */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
/* Pentium, Pentium OverDrive MMX, Pentium Mobile MMX: 3.3V (real Pentium Mobile MMX is 2.45V).
Pentium MMX: 2.8 V.
AMD K6 Model 6: 2.9 V for 166/200, 3.2 V for 233.
AMD K6 Model 7: 2.2 V. */
switch (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) {
case CPU_PENTIUMMMX:
machine_hwm.voltages[0] = 2800;
break;
case CPU_K6:
case CPU_K6_2:
machine_hwm.voltages[0] = 2200;
break;
}
hwm_set_values(machine_hwm);
device_add(&w83781d_device);
device_add(&w83781d_device); /* fans: Chassis, CPU, Power; temperatures: MB, unused, CPU */
hwm_values.temperatures[1] = 0; /* unused */
/* CPU offset */
if (hwm_values.temperatures[2] < 32) /* prevent underflow */
hwm_values.temperatures[2] = 0;
else
hwm_values.temperatures[2] -= 32;
return ret;
}
@@ -1014,41 +956,8 @@ machine_at_p5mms98_init(const machine_t *model)
device_add(&w83977tf_device);
device_add(&intel_flash_bxt_device);
spd_register(SPD_TYPE_SDRAM, 0x3, 128);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* Thermal */
3000, /* CPU */
3000 /* Chassis */
}, { /* temperatures */
0, /* unused */
30 /* CPU */
}, { /* voltages */
3300, /* VCORE (3.3V by default) */
3300, /* VIO (3.3V) */
3300, /* +3.3V */
RESISTOR_DIVIDER(5000, 11, 16), /* +5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10), /* +12V (28K/10K divider suggested in the W83781D datasheet) */
RESISTOR_DIVIDER(12000, 853, 347), /* -12V (divider values bruteforced) */
RESISTOR_DIVIDER(5000, 1, 2) /* -5V (divider values bruteforced) */
}
};
/* Pentium, Pentium OverDrive MMX, Pentium Mobile MMX: 3.3V (real Pentium Mobile MMX is 2.45V).
Pentium MMX: 2.8 V.
AMD K6 Model 6: 2.9 V for 166/200, 3.2 V for 233.
AMD K6 Model 7: 2.2 V. */
switch (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) {
case CPU_PENTIUMMMX:
machine_hwm.voltages[0] = 2800;
break;
case CPU_K6:
case CPU_K6_2:
machine_hwm.voltages[0] = 2200;
break;
}
hwm_set_values(machine_hwm);
device_add(&lm78_device);
device_add(&lm75_1_4a_device);
device_add(&lm78_device); /* fans: Thermal, CPU, Chassis; temperature: unused */
device_add(&lm75_1_4a_device); /* temperature: CPU */
return ret;
}

View File

@@ -83,7 +83,7 @@ machine_at_mb600n_init(const machine_t *model)
pci_init(PCI_CONFIG_TYPE_1);
pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0);
pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1);
pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2);
pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3);
@@ -209,7 +209,7 @@ machine_at_8500ttc_init(const machine_t *model)
pci_init(PCI_CONFIG_TYPE_1);
pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0);
pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1);
pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2);
pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3);
@@ -238,7 +238,7 @@ machine_at_m6mi_init(const machine_t *model)
pci_init(PCI_CONFIG_TYPE_1);
pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0);
pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1);
pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2);
pci_register_slot(0x0F, PCI_CARD_NORMAL, 4, 1, 2, 3);

View File

@@ -135,54 +135,6 @@ machine_at_ficva503a_init(const machine_t *model)
device_add(&via_vt82c686_sio_device);
device_add(&sst_flash_39sf020_device);
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
hwm_values_t machine_hwm = {
{ /* fan speeds */
3000, /* CPUFAN1 */
3000 /* ChassisFAN */
}, { /* temperatures */
32, /* CPU */
32, /* System */
0 /* unused */
}, { /* voltages */
3300, /* Vcore (3.3V by default) */
2500, /* 2.5V (unused) */
3300, /* 3.3V */
RESISTOR_DIVIDER(5000, 9, 16), /* 5V (divider values bruteforced) */
RESISTOR_DIVIDER(12000, 28, 10) /* 12V (28K/10K divider applies to W83781D but is close enough) */
}
};
/* Pentium, Pentium OverDrive MMX, Pentium Mobile MMX: 3.3V (real Pentium Mobile MMX is 2.45V).
Pentium MMX: 2.8 V.
AMD K6 Model 6: 2.9 V for 166/200, 3.2 V for 233.
AMD K6 Model 7: 2.2 V. */
switch (model->cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) {
case CPU_WINCHIP:
case CPU_WINCHIP2:
#if (defined(USE_NEW_DYNAREC) || (defined(DEV_BRANCH) && defined(USE_CYRIX_6X86)))
case CPU_Cx6x86:
#endif
#if defined(DEV_BRANCH) && defined(USE_AMD_K5)
case CPU_K5:
case CPU_5K86:
#endif
machine_hwm.voltages[0] = 3500;
break;
#if (defined(USE_NEW_DYNAREC) || (defined(DEV_BRANCH) && defined(USE_CYRIX_6X86)))
case CPU_Cx6x86MX:
machine_hwm.voltages[0] = 2900;
break;
#endif
case CPU_PENTIUMMMX:
machine_hwm.voltages[0] = 2800;
break;
case CPU_K6:
case CPU_K6_2:
machine_hwm.voltages[0] = 2200;
break;
}
machine_hwm.voltages[0] *= 1.32; /* multiplier bruteforced */
hwm_set_values(machine_hwm);
device_add(&via_vt82c686_hwm_device);
return ret;

View File

@@ -331,21 +331,28 @@ void
pci_set_mirq(uint8_t mirq, int level)
{
uint8_t irq_line = 0;
uint8_t irq_bit;
if (! pci_mirqs[mirq].enabled) {
pci_log("pci_set_mirq(%02X): MIRQ0 disabled\n", mirq);
return;
if (mirq >= 0xf0) {
irq_line = mirq & 0x0f;
irq_bit = 0x1D;
} else {
if (! pci_mirqs[mirq].enabled) {
pci_log("pci_set_mirq(%02X): MIRQ0 disabled\n", mirq);
return;
}
if (pci_mirqs[mirq].irq_line > 0x0f) {
pci_log("pci_set_mirq(%02X): IRQ line is disabled\n", mirq);
return;
}
irq_line = pci_mirqs[mirq].irq_line;
irq_bit = (0x1E + mirq);
}
if (pci_mirqs[mirq].irq_line > 0x0f) {
pci_log("pci_set_mirq(%02X): IRQ line is disabled\n", mirq);
return;
}
irq_line = pci_mirqs[mirq].irq_line;
pci_log("pci_set_mirq(%02X): Using IRQ %i\n", mirq, irq_line);
if (level && (pci_irq_hold[irq_line] & (1ULL << (0x1E + mirq)))) {
if (level && (pci_irq_hold[irq_line] & (1ULL << irq_bit))) {
/* IRQ already held, do nothing. */
pci_log("pci_set_mirq(%02X): MIRQ is already holding the IRQ\n", mirq);
return;
@@ -367,7 +374,7 @@ pci_set_mirq(uint8_t mirq, int level)
/* If the IRQ is level-triggered, mark that this MIRQ is holding it. */
if (level) {
pci_log("pci_set_mirq(%02X): Marking that this card is holding the IRQ\n", mirq);
pci_irq_hold[irq_line] |= (1ULL << (0x1E + mirq));
pci_irq_hold[irq_line] |= (1ULL << irq_bit);
}
pci_log("pci_set_mirq(%02X): Edge-triggered interrupt, not marking\n", mirq);
@@ -450,26 +457,33 @@ void
pci_clear_mirq(uint8_t mirq, int level)
{
uint8_t irq_line = 0;
uint8_t irq_bit;
if (mirq > 1) {
pci_log("pci_clear_mirq(%02X): Invalid MIRQ\n", mirq);
return;
if (mirq >= 0xf0) {
irq_line = mirq & 0x0f;
irq_bit = 0x1D;
} else {
if (mirq > 1) {
pci_log("pci_clear_mirq(%02X): Invalid MIRQ\n", mirq);
return;
}
if (! pci_mirqs[mirq].enabled) {
pci_log("pci_clear_mirq(%02X): MIRQ0 disabled\n", mirq);
return;
}
if (pci_mirqs[mirq].irq_line > 0x0f) {
pci_log("pci_clear_mirq(%02X): IRQ line is disabled\n", mirq);
return;
}
irq_line = pci_mirqs[mirq].irq_line;
irq_bit = (0x1E + mirq);
}
if (! pci_mirqs[mirq].enabled) {
pci_log("pci_clear_mirq(%02X): MIRQ0 disabled\n", mirq);
return;
}
if (pci_mirqs[mirq].irq_line > 0x0f) {
pci_log("pci_clear_mirq(%02X): IRQ line is disabled\n", mirq);
return;
}
irq_line = pci_mirqs[mirq].irq_line;
pci_log("pci_clear_mirq(%02X): Using IRQ %i\n", mirq, irq_line);
if (level && !(pci_irq_hold[irq_line] & (1ULL << (0x1E + mirq)))) {
if (level && !(pci_irq_hold[irq_line] & (1ULL << irq_bit))) {
/* IRQ not held, do nothing. */
pci_log("pci_clear_mirq(%02X): MIRQ is not holding the IRQ\n", mirq);
return;
@@ -477,7 +491,7 @@ pci_clear_mirq(uint8_t mirq, int level)
if (level) {
pci_log("pci_clear_mirq(%02X): Releasing this MIRQ's hold on the IRQ\n", mirq);
pci_irq_hold[irq_line] &= ~(1 << (0x1E + mirq));
pci_irq_hold[irq_line] &= ~(1 << irq_bit);
if (! pci_irq_hold[irq_line]) {
pci_log("pci_clear_mirq(%02X): IRQ no longer held by any card, clearing it\n", mirq);

View File

@@ -62,6 +62,7 @@ vt82c686_fdc_handler(vt82c686_t *dev)
if (dev->regs[0x02] & 0x10)
fdc_set_base(dev->fdc, io_base);
fdc_set_dma_ch(dev->fdc, dev->fdc_dma);
fdc_set_irq(dev->fdc, dev->fdc_irq);
}
@@ -104,19 +105,24 @@ vt82c686_write(uint16_t port, uint8_t val, void *priv)
return;
if (!(port & 1)) {
/* Registers start at 0xE0 but we cut them down to start at 0x00. */
dev->cur_reg = (val & 0x1f);
dev->cur_reg = val;
return;
}
/* NOTE: Registers are [0xE0:0xFF] but we store them as [0x00:0x1F]. */
if (dev->cur_reg < 0xe0)
return;
uint8_t reg = dev->cur_reg & 0x1f;
/* Read-only registers */
if ((dev->cur_reg < 0x02) || (dev->cur_reg == 0x04) || (dev->cur_reg == 0x05) || ((dev->cur_reg >= 0xe9) && (dev->cur_reg < 0xee)) ||
(dev->cur_reg == 0xf3) || (dev->cur_reg == 0xf5) || (dev->cur_reg == 0xf7) || (dev->cur_reg >= 0xf9))
if ((reg < 0x02) || (reg == 0x04) || (reg == 0x05) || ((reg >= 0x09) && (reg < 0x0e)) ||
(reg == 0x13) || (reg == 0x15) || (reg == 0x17) || (reg >= 0x19))
return;
switch (dev->cur_reg) {
dev->regs[reg] = val;
switch (reg) {
case 0x02:
dev->regs[dev->cur_reg] = val;
vt82c686_lpt_handler(dev);
vt82c686_serial_handler(dev, 0);
vt82c686_serial_handler(dev, 1);
@@ -124,28 +130,20 @@ vt82c686_write(uint16_t port, uint8_t val, void *priv)
break;
case 0x03:
dev->regs[dev->cur_reg] = val;
vt82c686_fdc_handler(dev);
break;
case 0x06:
dev->regs[dev->cur_reg] = val;
vt82c686_lpt_handler(dev);
break;
case 0x07:
dev->regs[dev->cur_reg] = val;
vt82c686_serial_handler(dev, 0);
break;
case 0x08:
dev->regs[dev->cur_reg] = val;
vt82c686_serial_handler(dev, 1);
break;
default:
dev->regs[dev->cur_reg] = val;
break;
}
}
@@ -156,10 +154,13 @@ vt82c686_read(uint16_t port, void *priv)
vt82c686_t *dev = (vt82c686_t *) priv;
uint8_t ret = 0xff;
/* NOTE: Registers are [0xE0:0xFF] but we store them as [0x00:0x1F]. */
if (!(port & 1))
ret = dev->cur_reg | 0xe0;
ret = dev->cur_reg;
else if (dev->cur_reg < 0xe0)
ret = 0xff;
else
ret = dev->regs[dev->cur_reg];
ret = dev->regs[dev->cur_reg & 0x1f];
return ret;
}