From 886dbe09ea48eeed45053d67fc3fde866a2c90c8 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 20 Nov 2020 01:22:04 -0300 Subject: [PATCH 01/16] DDC/I2C/SMBus overhaul (incomplete, commit for the night) --- src/device/hwm_gl518sm.c | 52 ++-- src/device/hwm_lm75.c | 60 ++-- src/device/hwm_lm78.c | 92 +++--- src/device/hwm_vt82c686.c | 1 - src/device/i2c.c | 496 +++++++++++++++++++++++++++++++++ src/device/i2c_gpio.c | 277 ++++++++++++++++++ src/device/smbus.c | 403 --------------------------- src/device/smbus_piix4.c | 56 ++-- src/include/86box/hwm.h | 4 +- src/include/86box/i2c.h | 89 ++++++ src/include/86box/smbus.h | 67 ----- src/include/86box/vid_ddc.h | 28 +- src/mem/spd.c | 472 ++++++++++++++++--------------- src/video/vid_ati_mach64.c | 14 +- src/video/vid_ddc.c | 362 ++++++------------------ src/video/vid_s3_virge.c | 12 +- src/video/vid_voodoo_banshee.c | 13 +- src/win/Makefile.mingw | 2 +- 18 files changed, 1368 insertions(+), 1132 deletions(-) create mode 100644 src/device/i2c.c create mode 100644 src/device/i2c_gpio.c delete mode 100644 src/device/smbus.c create mode 100644 src/include/86box/i2c.h delete mode 100644 src/include/86box/smbus.h diff --git a/src/device/hwm_gl518sm.c b/src/device/hwm_gl518sm.c index ce347655e..45353cd0d 100644 --- a/src/device/hwm_gl518sm.c +++ b/src/device/hwm_gl518sm.c @@ -24,7 +24,7 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> -#include <86box/smbus.h> +#include <86box/i2c.h> #include <86box/hwm.h> @@ -41,17 +41,17 @@ typedef struct { uint16_t regs[32]; uint8_t addr_register; - uint8_t smbus_addr; + uint8_t i2c_addr; } gl518sm_t; -static uint8_t gl518sm_smbus_read_byte(uint8_t addr, void *priv); -static uint8_t gl518sm_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv); -static uint16_t gl518sm_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv); +static uint8_t gl518sm_i2c_read_byte(void *bus, uint8_t addr, void *priv); +static uint8_t gl518sm_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv); +static uint16_t gl518sm_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv); static uint16_t gl518sm_read(gl518sm_t *dev, uint8_t reg); -static void gl518sm_smbus_write_byte(uint8_t addr, uint8_t val, void *priv); -static void gl518sm_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv); -static void gl518sm_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv); +static void gl518sm_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv); +static void gl518sm_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv); +static void gl518sm_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv); static uint8_t gl518sm_write(gl518sm_t *dev, uint8_t reg, uint16_t val); static void gl518sm_reset(gl518sm_t *dev); @@ -79,24 +79,24 @@ gl518sm_log(const char *fmt, ...) static void gl518sm_remap(gl518sm_t *dev, uint8_t addr) { - gl518sm_log("GL518SM: remapping to SMBus %02Xh\n", addr); + gl518sm_log("GL518SM: remapping to I2C %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); + i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, + NULL, gl518sm_i2c_read_byte, gl518sm_i2c_read_byte_cmd, gl518sm_i2c_read_word_cmd, NULL, + NULL, gl518sm_i2c_write_byte, gl518sm_i2c_write_byte_cmd, gl518sm_i2c_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); + if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1, + NULL, gl518sm_i2c_read_byte, gl518sm_i2c_read_byte_cmd, gl518sm_i2c_read_word_cmd, NULL, + NULL, gl518sm_i2c_write_byte, gl518sm_i2c_write_byte_cmd, gl518sm_i2c_write_word_cmd, NULL, + dev); - dev->smbus_addr = addr; + dev->i2c_addr = addr; } static uint8_t -gl518sm_smbus_read_byte(uint8_t addr, void *priv) +gl518sm_i2c_read_byte(void *bus, uint8_t addr, void *priv) { gl518sm_t *dev = (gl518sm_t *) priv; return gl518sm_read(dev, dev->addr_register); @@ -104,7 +104,7 @@ gl518sm_smbus_read_byte(uint8_t addr, void *priv) static uint8_t -gl518sm_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) +gl518sm_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) { gl518sm_t *dev = (gl518sm_t *) priv; return gl518sm_read(dev, cmd); @@ -112,7 +112,7 @@ gl518sm_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) static uint16_t -gl518sm_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv) +gl518sm_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) { gl518sm_t *dev = (gl518sm_t *) priv; return gl518sm_read(dev, cmd); @@ -168,7 +168,7 @@ gl518sm_read(gl518sm_t *dev, uint8_t reg) static void -gl518sm_smbus_write_byte(uint8_t addr, uint8_t val, void *priv) +gl518sm_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv) { gl518sm_t *dev = (gl518sm_t *) priv; dev->addr_register = val; @@ -176,7 +176,7 @@ gl518sm_smbus_write_byte(uint8_t addr, uint8_t val, void *priv) static void -gl518sm_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv) +gl518sm_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv) { gl518sm_t *dev = (gl518sm_t *) priv; gl518sm_write(dev, cmd, val); @@ -184,7 +184,7 @@ gl518sm_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv) static void -gl518sm_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv) +gl518sm_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv) { gl518sm_t *dev = (gl518sm_t *) priv; gl518sm_write(dev, cmd, val); @@ -290,7 +290,7 @@ gl518sm_init(const device_t *info) } -/* GL518SM on SMBus address 2Ch */ +/* GL518SM on I2C address 2Ch */ const device_t gl518sm_2c_device = { "Genesys Logic GL518SM Hardware Monitor", DEVICE_ISA, @@ -300,7 +300,7 @@ const device_t gl518sm_2c_device = { NULL }; -/* GL518SM on SMBus address 2Dh */ +/* GL518SM on I2C address 2Dh */ const device_t gl518sm_2d_device = { "Genesys Logic GL518SM Hardware Monitor", DEVICE_ISA, diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index 9f48bfb78..57a8781f9 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -23,19 +23,19 @@ #include #include <86box/86box.h> #include <86box/device.h> -#include <86box/smbus.h> +#include <86box/i2c.h> #include <86box/hwm.h> #define LM75_TEMP_TO_REG(t) ((t) << 8) -static uint8_t lm75_smbus_read_byte(uint8_t addr, void *priv); -static uint8_t lm75_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv); -static uint16_t lm75_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv); -static void lm75_smbus_write_byte(uint8_t addr, uint8_t val, void *priv); -static void lm75_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv); -static void lm75_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv); +static uint8_t lm75_i2c_read_byte(void *bus, uint8_t addr, void *priv); +static uint8_t lm75_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv); +static uint16_t lm75_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv); +static void lm75_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv); +static void lm75_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv); +static void lm75_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv); static void lm75_reset(lm75_t *dev); @@ -62,24 +62,24 @@ lm75_log(const char *fmt, ...) void lm75_remap(lm75_t *dev, uint8_t addr) { - lm75_log("LM75: remapping to SMBus %02Xh\n", addr); + lm75_log("LM75: remapping to I2C %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); + if (dev->i2c_addr < 0x80) i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, + NULL, lm75_i2c_read_byte, lm75_i2c_read_byte_cmd, lm75_i2c_read_word_cmd, NULL, + NULL, lm75_i2c_write_byte, lm75_i2c_write_byte_cmd, lm75_i2c_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); + if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1, + NULL, lm75_i2c_read_byte, lm75_i2c_read_byte_cmd, lm75_i2c_read_word_cmd, NULL, + NULL, lm75_i2c_write_byte, lm75_i2c_write_byte_cmd, lm75_i2c_write_word_cmd, NULL, + dev); - dev->smbus_addr = addr; + dev->i2c_addr = addr; } static uint8_t -lm75_smbus_read_byte(uint8_t addr, void *priv) +lm75_i2c_read_byte(void *bus, uint8_t addr, void *priv) { lm75_t *dev = (lm75_t *) priv; return lm75_read(dev, dev->addr_register); @@ -87,14 +87,14 @@ lm75_smbus_read_byte(uint8_t addr, void *priv) static uint8_t -lm75_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) +lm75_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) { lm75_t *dev = (lm75_t *) priv; return lm75_read(dev, cmd); } static uint16_t -lm75_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv) +lm75_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) { lm75_t *dev = (lm75_t *) priv; uint8_t rethi = 0; @@ -129,9 +129,9 @@ lm75_read(lm75_t *dev, uint8_t reg) /* The AS99127F hardware monitor uses the addresses of its LM75 devices 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); + the main monitor address through an internal I2C call, if necessary. */ + if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) + ret = i2c_read_byte_cmd(i2c_smbus, dev->as99127f_i2c_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 */ @@ -146,7 +146,7 @@ lm75_read(lm75_t *dev, uint8_t reg) static void -lm75_smbus_write_byte(uint8_t addr, uint8_t val, void *priv) +lm75_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv) { lm75_t *dev = (lm75_t *) priv; dev->addr_register = val; @@ -154,7 +154,7 @@ lm75_smbus_write_byte(uint8_t addr, uint8_t val, void *priv) static void -lm75_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv) +lm75_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv) { lm75_t *dev = (lm75_t *) priv; lm75_write(dev, cmd, val); @@ -162,7 +162,7 @@ lm75_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv) static void -lm75_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv) +lm75_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv) { lm75_t *dev = (lm75_t *) priv; uint8_t valhi = (val >> 8); @@ -196,9 +196,9 @@ lm75_write(lm75_t *dev, uint8_t reg, uint8_t val) /* The AS99127F hardware monitor uses the addresses of its LM75 devices 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); + the main monitor address through an internal I2C call, if necessary. */ + if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) { + i2c_write_byte_cmd(i2c_smbus, dev->as99127f_i2c_addr, reg, val); return 1; } @@ -247,7 +247,7 @@ lm75_init(const device_t *info) hwm_values.temperatures[dev->local >> 8] = 30; dev->values = &hwm_values; - dev->as99127f_smbus_addr = 0x80; + dev->as99127f_i2c_addr = 0x80; lm75_reset(dev); diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index 8e133ffbd..5817452d3 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -25,11 +25,11 @@ #include <86box/device.h> #include <86box/io.h> #include "cpu.h" -#include <86box/smbus.h> +#include <86box/i2c.h> #include <86box/hwm.h> -#define LM78_SMBUS 0x010000 +#define LM78_I2C 0x010000 #define LM78_W83781D 0x020000 #define LM78_AS99127F_REV1 0x040000 #define LM78_AS99127F_REV2 0x080000 @@ -56,19 +56,19 @@ typedef struct { uint8_t addr_register; uint8_t data_register; - uint8_t smbus_addr; + uint8_t i2c_addr; } lm78_t; static uint8_t lm78_isa_read(uint16_t port, void *priv); -static uint8_t lm78_smbus_read_byte(uint8_t addr, void *priv); -static uint8_t lm78_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv); -static uint16_t lm78_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv); +static uint8_t lm78_i2c_read_byte(void *bus, uint8_t addr, void *priv); +static uint8_t lm78_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv); +static uint16_t lm78_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv); static uint8_t lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank); static void lm78_isa_write(uint16_t port, uint8_t val, void *priv); -static void lm78_smbus_write_byte(uint8_t addr, uint8_t val, void *priv); -static void lm78_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv); -static void lm78_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv); +static void lm78_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv); +static void lm78_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv); +static void lm78_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv); static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank); static void lm78_reset(lm78_t *dev, uint8_t initialization); @@ -98,29 +98,29 @@ lm78_remap(lm78_t *dev, uint8_t addr) { lm75_t *lm75; - if (!(dev->local & LM78_SMBUS)) return; + if (!(dev->local & LM78_I2C)) return; - lm78_log("LM78: remapping to SMBus %02Xh\n", addr); + lm78_log("LM78: remapping to I2C %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); + i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, + NULL, lm78_i2c_read_byte, lm78_i2c_read_byte_cmd, lm78_i2c_read_word_cmd, NULL, + NULL, lm78_i2c_write_byte, lm78_i2c_write_byte_cmd, lm78_i2c_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); + if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1, + NULL, lm78_i2c_read_byte, lm78_i2c_read_byte_cmd, lm78_i2c_read_word_cmd, NULL, + NULL, lm78_i2c_write_byte, lm78_i2c_write_byte_cmd, lm78_i2c_write_word_cmd, NULL, + dev); - dev->smbus_addr = addr; + dev->i2c_addr = addr; if (dev->local & LM78_AS99127F) { - /* Store the main SMBus address on the LM75 devices to ensure reads/writes + /* Store the main I2C 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; + lm75->as99127f_i2c_addr = dev->i2c_addr; } } } @@ -159,7 +159,7 @@ lm78_isa_read(uint16_t port, void *priv) static uint8_t -lm78_smbus_read_byte(uint8_t addr, void *priv) +lm78_i2c_read_byte(void *bus, uint8_t addr, void *priv) { lm78_t *dev = (lm78_t *) priv; return lm78_read(dev, dev->addr_register, LM78_WINBOND_BANK); @@ -167,7 +167,7 @@ lm78_smbus_read_byte(uint8_t addr, void *priv) static uint8_t -lm78_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) +lm78_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) { lm78_t *dev = (lm78_t *) priv; return lm78_read(dev, cmd, LM78_WINBOND_BANK); @@ -175,7 +175,7 @@ lm78_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) static uint16_t -lm78_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv) +lm78_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) { lm78_t *dev = (lm78_t *) priv; return (lm78_read(dev, cmd, LM78_WINBOND_BANK) << 8) | lm78_read(dev, cmd, LM78_WINBOND_BANK); @@ -265,7 +265,7 @@ lm78_isa_write(uint16_t port, uint8_t val, void *priv) static void -lm78_smbus_write_byte(uint8_t addr, uint8_t val, void *priv) +lm78_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv) { lm78_t *dev = (lm78_t *) priv; dev->addr_register = val; @@ -273,7 +273,7 @@ lm78_smbus_write_byte(uint8_t addr, uint8_t val, void *priv) static void -lm78_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv) +lm78_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv) { lm78_t *dev = (lm78_t *) priv; lm78_write(dev, cmd, val, LM78_WINBOND_BANK); @@ -281,7 +281,7 @@ lm78_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv) static void -lm78_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv) +lm78_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv) { lm78_t *dev = (lm78_t *) priv; lm78_write(dev, cmd, val, LM78_WINBOND_BANK); @@ -354,13 +354,13 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank) switch (reg) { case 0x40: - if (val & 0x80) /* INITIALIZATION bit resets all registers except main SMBus address */ + if (val & 0x80) /* INITIALIZATION bit resets all registers except main I2C address */ lm78_reset(dev, 1); break; case 0x48: - /* set main SMBus address */ - if (dev->local & LM78_SMBUS) + /* set main I2C address */ + if (dev->local & LM78_I2C) lm78_remap(dev, dev->regs[0x48] & 0x7f); break; @@ -376,8 +376,8 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank) break; case 0x4a: - /* set LM75 SMBus addresses (Winbond only) */ - if (dev->local & LM78_SMBUS) { + /* set LM75 I2C addresses (Winbond only) */ + if (dev->local & LM78_I2C) { for (uint8_t i = 0; i <= 1; i++) { lm75 = device_get_priv(dev->lm75[i]); if (!lm75) @@ -412,10 +412,10 @@ lm78_reset(lm78_t *dev, uint8_t initialization) 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_I2C) { + if (!initialization) /* don't reset main I2C address if the reset was triggered by the INITIALIZATION bit */ + dev->i2c_addr = 0x2d; + dev->regs[0x48] = dev->i2c_addr; if (dev->local & LM78_WINBOND) dev->regs[0x4a] = 0x01; } else { @@ -469,7 +469,7 @@ lm78_reset(lm78_t *dev, uint8_t initialization) dev->regs[0x49] = 0x40; } - lm78_remap(dev, dev->smbus_addr); + lm78_remap(dev, dev->i2c_addr); } @@ -519,7 +519,7 @@ lm78_init(const device_t *info) /* Set chip-specific default values. */ if (dev->local & LM78_AS99127F) { - /* AS99127: different -12V Rin value (bruteforced) */ + /* AS99127: different -12V Rin value (bruteforced) */ defaults.voltages[5] = LM78_NEG_VOLTAGE(12000, 2400); } else if (dev->local & LM78_W83782D) { /* W83782D: different negative voltage formula */ @@ -536,7 +536,7 @@ lm78_init(const device_t *info) 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) + if (dev->local & LM78_I2C) dev->lm75[i]->local |= 0x48 + i; device_add(dev->lm75[i]); } else { @@ -558,7 +558,7 @@ lm78_init(const device_t *info) const device_t lm78_device = { "National Semiconductor LM78 Hardware Monitor", DEVICE_ISA, - 0x290 | LM78_SMBUS, + 0x290 | LM78_I2C, lm78_init, lm78_close, NULL, { NULL }, NULL, NULL, NULL @@ -569,19 +569,19 @@ const device_t lm78_device = { const device_t w83781d_device = { "Winbond W83781D Hardware Monitor", DEVICE_ISA, - 0x290 | LM78_SMBUS | LM78_W83781D, + 0x290 | LM78_I2C | LM78_W83781D, lm78_init, lm78_close, NULL, { NULL }, NULL, NULL, NULL }; -/* The ASUS AS99127F is a customized W83781D with no ISA interface (SMBus +/* The ASUS AS99127F is a customized W83781D with no ISA interface (I2C only), added proprietary registers and different chip/vendor IDs. */ const device_t as99127f_device = { "ASUS AS99127F Rev. 1 Hardware Monitor", DEVICE_ISA, - LM78_SMBUS | LM78_AS99127F_REV1, + LM78_I2C | LM78_AS99127F_REV1, lm78_init, lm78_close, NULL, { NULL }, NULL, NULL, NULL @@ -592,7 +592,7 @@ const device_t as99127f_device = { const device_t as99127f_rev2_device = { "ASUS AS99127F Rev. 2 Hardware Monitor", DEVICE_ISA, - LM78_SMBUS | LM78_AS99127F_REV2, + LM78_I2C | LM78_AS99127F_REV2, lm78_init, lm78_close, NULL, { NULL }, NULL, NULL, NULL @@ -603,7 +603,7 @@ const device_t as99127f_rev2_device = { const device_t w83782d_device = { "Winbond W83782D Hardware Monitor", DEVICE_ISA, - 0x290 | LM78_SMBUS | LM78_W83782D, + 0x290 | LM78_I2C | LM78_W83782D, lm78_init, lm78_close, NULL, { NULL }, NULL, NULL, NULL diff --git a/src/device/hwm_vt82c686.c b/src/device/hwm_vt82c686.c index d91c0aab7..70a01a6ac 100644 --- a/src/device/hwm_vt82c686.c +++ b/src/device/hwm_vt82c686.c @@ -24,7 +24,6 @@ #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> -#include <86box/smbus.h> #include <86box/hwm.h> diff --git a/src/device/i2c.c b/src/device/i2c.c new file mode 100644 index 000000000..20201c990 --- /dev/null +++ b/src/device/i2c.c @@ -0,0 +1,496 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implement the I2C bus and its operations. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/i2c.h> + + +#define NADDRS 128 /* I2C supports 128 addresses */ +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + + +typedef struct _i2c_ { + void (*read_quick)(void *bus, uint8_t addr, void *priv); + uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv); + uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv); + uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv); + uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv); + + void (*write_quick)(void *bus, uint8_t addr, void *priv); + void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv); + void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv); + void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv); + void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv); + + void *priv; + + struct _i2c_ *prev, *next; +} i2c_t; + +typedef struct { + char *name; + i2c_t *devices[NADDRS], *last[NADDRS]; +} i2c_bus_t; + + +void *i2c_smbus; + +#define ENABLE_I2C_LOG 1 +#ifdef ENABLE_I2C_LOG +int i2c_do_log = ENABLE_I2C_LOG; + + +static void +i2c_log(const char *fmt, ...) +{ + va_list ap; + + if (i2c_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define i2c_log(fmt, ...) +#endif + + +void * +i2c_addbus(char *name) +{ + i2c_bus_t *bus = (i2c_bus_t *) malloc(sizeof(i2c_bus_t)); + memset(bus, 0, sizeof(i2c_bus_t)); + + bus->name = name; + + return bus; +} + + +void +i2c_removebus(void *bus_handle) +{ + if (!bus_handle) + return; + + free(bus_handle); +} + + +void +i2c_sethandler(void *bus_handle, uint8_t base, int size, + void (*read_quick)(void *bus, uint8_t addr, void *priv), + uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv), + uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), + uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), + uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void (*write_quick)(void *bus, uint8_t addr, void *priv), + void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv), + void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv), + void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv), + void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void *priv) +{ + int c; + i2c_t *p, *q = NULL; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + + if (!bus_handle || ((base + size) >= NADDRS)) + return; + + for (c = 0; c < size; c++) { + p = bus->last[base + c]; + q = (i2c_t *) malloc(sizeof(i2c_t)); + memset(q, 0, sizeof(i2c_t)); + if (p) { + p->next = q; + q->prev = p; + } else { + bus->devices[base + c] = q; + q->prev = NULL; + } + + q->read_byte = read_byte; + q->read_byte_cmd = read_byte_cmd; + q->read_word_cmd = read_word_cmd; + q->read_block_cmd = read_block_cmd; + + q->write_byte = write_byte; + q->write_byte_cmd = write_byte_cmd; + q->write_word_cmd = write_word_cmd; + q->write_block_cmd = write_block_cmd; + + q->priv = priv; + q->next = NULL; + + bus->last[base + c] = q; + } +} + + +void +i2c_removehandler(void *bus_handle, uint8_t base, int size, + void (*read_quick)(void *bus, uint8_t addr, void *priv), + uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv), + uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), + uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), + uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void (*write_quick)(void *bus, uint8_t addr, void *priv), + void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv), + void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv), + void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv), + void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void *priv) +{ + int c; + i2c_t *p, *q; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + + if (!bus_handle || ((base + size) >= NADDRS)) + return; + + for (c = 0; c < size; c++) { + p = bus->devices[base + c]; + if (!p) + continue; + while(p) { + q = p->next; + if ((p->read_byte == read_byte) && (p->read_byte_cmd == read_byte_cmd) && + (p->read_word_cmd == read_word_cmd) && (p->read_block_cmd == read_block_cmd) && + (p->write_byte == write_byte) && (p->write_byte_cmd == write_byte_cmd) && + (p->write_word_cmd == write_word_cmd) && (p->write_block_cmd == write_block_cmd) && + (p->priv == priv)) { + if (p->prev) + p->prev->next = p->next; + else + bus->devices[base + c] = p->next; + if (p->next) + p->next->prev = p->prev; + else + bus->last[base + c] = p->prev; + free(p); + p = NULL; + break; + } + p = q; + } + } +} + + +void +i2c_handler(int set, void *bus_handle, uint8_t base, int size, + void (*read_quick)(void *bus, uint8_t addr, void *priv), + uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv), + uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), + uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), + uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void (*write_quick)(void *bus, uint8_t addr, void *priv), + void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv), + void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv), + void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv), + void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void *priv) +{ + if (set) + i2c_sethandler(bus_handle, base, size, read_quick, read_byte, read_byte_cmd, read_word_cmd, read_block_cmd, write_quick, write_byte, write_byte_cmd, write_word_cmd, write_block_cmd, priv); + else + i2c_removehandler(bus_handle, base, size, read_quick, read_byte, read_byte_cmd, read_word_cmd, read_block_cmd, write_quick, write_byte, write_byte_cmd, write_word_cmd, write_block_cmd, priv); +} + + +uint8_t +i2c_has_device(void *bus_handle, uint8_t addr) +{ + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + + if (!bus) + return 0; + + return(!!bus->devices[addr]); +} + + +void +i2c_read_quick(void *bus_handle, uint8_t addr) +{ + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + i2c_t *p; + int found = 0; + + if (!bus) + return; + + p = bus->devices[addr]; + if (p) { + while(p) { + if (p->read_byte) { + p->read_quick(bus_handle, addr, p->priv); + found++; + } + p = p->next; + } + } + + i2c_log("I2C: read_quick(%s, %02X)\n", bus->name, addr); +} + + +uint8_t +i2c_read_byte(void *bus_handle, uint8_t addr) +{ + uint8_t ret = 0xff; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + i2c_t *p; + int found = 0; + + if (!bus) + return(ret); + + p = bus->devices[addr]; + if (p) { + while(p) { + if (p->read_byte) { + ret &= p->read_byte(bus_handle, addr, p->priv); + found++; + } + p = p->next; + } + } + + i2c_log("I2C: read_byte(%s, %02X) = %02X\n", bus->name, addr, ret); + + return(ret); +} + +uint8_t +i2c_read_byte_cmd(void *bus_handle, uint8_t addr, uint8_t cmd) +{ + uint8_t ret = 0xff; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + i2c_t *p; + int found = 0; + + if (!bus) + return(ret); + + p = bus->devices[addr]; + if (p) { + while(p) { + if (p->read_byte_cmd) { + ret &= p->read_byte_cmd(bus_handle, addr, cmd, p->priv); + found++; + } + p = p->next; + } + } + + i2c_log("I2C: read_byte_cmd(%s, %02X, %02X) = %02X\n", bus->name, addr, cmd, ret); + + return(ret); +} + +uint16_t +i2c_read_word_cmd(void *bus_handle, uint8_t addr, uint8_t cmd) +{ + uint16_t ret = 0xffff; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + i2c_t *p; + int found = 0; + + if (!bus) + return(ret); + + p = bus->devices[addr]; + if (p) { + while(p) { + if (p->read_word_cmd) { + ret &= p->read_word_cmd(bus_handle, addr, cmd, p->priv); + found++; + } + p = p->next; + } + } + + i2c_log("I2C: read_word_cmd(%s, %02X, %02X) = %04X\n", bus->name, addr, cmd, ret); + + return(ret); +} + +uint8_t +i2c_read_block_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len) +{ + uint8_t ret = 0; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + i2c_t *p; + int found = 0; + + if (!bus) + return(ret); + + p = bus->devices[addr]; + if (p) { + while(p) { + if (p->read_block_cmd) { + ret = MAX(ret, p->read_block_cmd(bus_handle, addr, cmd, data, len, p->priv)); + found++; + } + p = p->next; + } + } + + i2c_log("I2C: read_block_cmd(%s, %02X, %02X) = %02X\n", bus->name, addr, cmd, len); + + return(ret); +} + + +void +i2c_write_quick(void *bus_handle, uint8_t addr) +{ + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + i2c_t *p; + int found = 0; + + if (!bus) + return; + + p = bus->devices[addr]; + if (p) { + while(p) { + if (p->read_byte) { + p->write_quick(bus_handle, addr, p->priv); + found++; + } + p = p->next; + } + } + + i2c_log("I2C: write_quick(%s, %02X)\n", bus->name, addr); +} + + +void +i2c_write_byte(void *bus_handle, uint8_t addr, uint8_t val) +{ + i2c_t *p; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + int found = 0; + + if (!bus) + return; + + if (bus->devices[addr]) { + p = bus->devices[addr]; + while(p) { + if (p->write_byte) { + p->write_byte(bus_handle, addr, val, p->priv); + found++; + } + p = p->next; + } + } + + i2c_log("I2C: write_byte(%s, %02X, %02X)\n", bus->name, addr, val); + + return; +} + +void +i2c_write_byte_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t val) +{ + i2c_t *p; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + int found = 0; + + if (!bus) + return; + + if (bus->devices[addr]) { + p = bus->devices[addr]; + while(p) { + if (p->write_byte_cmd) { + p->write_byte_cmd(bus_handle, addr, cmd, val, p->priv); + found++; + } + p = p->next; + } + } + + i2c_log("I2C: write_byte_cmd(%s, %02X, %02X, %02X)\n", bus->name, addr, cmd, val); + + return; +} + +void +i2c_write_word_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint16_t val) +{ + i2c_t *p; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + int found = 0; + + if (!bus) + return; + + if (bus->devices[addr]) { + p = bus->devices[addr]; + while(p) { + if (p->write_word_cmd) { + p->write_word_cmd(bus_handle, addr, cmd, val, p->priv); + found++; + } + p = p->next; + } + } + + i2c_log("I2C: write_word_cmd(%s, %02X, %02X, %04X)\n", bus->name, addr, cmd, val); + + return; +} + +void +i2c_write_block_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len) +{ + i2c_t *p; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + int found = 0; + + if (!bus) + return; + + p = bus->devices[addr]; + if (p) { + while(p) { + if (p->write_block_cmd) { + p->write_block_cmd(bus_handle, addr, cmd, data, len, p->priv); + found++; + } + p = p->next; + } + } + + i2c_log("I2C: write_block_cmd(%s, %02X, %02X, %02X)\n", bus->name, addr, cmd, len); + + return; +} diff --git a/src/device/i2c_gpio.c b/src/device/i2c_gpio.c new file mode 100644 index 000000000..decf52117 --- /dev/null +++ b/src/device/i2c_gpio.c @@ -0,0 +1,277 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of a GPIO-based I2C device. + * + * + * + * Authors: Sarah Walker, + * RichardG, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/i2c.h> + + +enum { + TRANSMITTER_SLAVE = 1, + TRANSMITTER_MASTER = 2 +}; + +enum { + I2C_IDLE = 0, + I2C_RECEIVE, + I2C_RECEIVE_WAIT, + I2C_TRANSMIT_START, + I2C_TRANSMIT, + I2C_ACKNOWLEDGE, + I2C_TRANSACKNOWLEDGE, + I2C_TRANSMIT_WAIT +}; + +enum { + SLAVE_IDLE = 0, + SLAVE_RECEIVEADDR, + SLAVE_RECEIVEDATA, + SLAVE_SENDDATA, + SLAVE_INVALID +}; + +typedef struct { + void *i2c; + uint8_t scl, sda, state, slave_state, slave_addr, slave_reg, + slave_writing, slave_rw, last_sda, pos, transmit, byte; +} i2c_gpio_t; + + +void * +i2c_gpio_init(char *bus_name) +{ + i2c_gpio_t *dev = (i2c_gpio_t *) malloc(sizeof(i2c_gpio_t)); + memset(dev, 0, sizeof(i2c_gpio_t)); + + dev->i2c = i2c_addbus(bus_name); + dev->scl = dev->sda = 1; + + return dev; +} + + +void +i2c_gpio_close(void *dev_handle) +{ + i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; + + i2c_removebus(dev->i2c); + + free(dev); +} + + +void +i2c_gpio_next_byte(i2c_gpio_t *dev) +{ + dev->byte = i2c_read_byte(dev->i2c, dev->slave_addr); +} + + +void +i2c_gpio_write(i2c_gpio_t *dev) +{ + switch (dev->slave_state) { + case SLAVE_IDLE: + dev->slave_addr = dev->byte >> 1; + if (!i2c_has_device(dev->i2c, dev->slave_addr)) { + dev->slave_state = SLAVE_INVALID; + break; + } + dev->slave_rw = dev->byte & 1; + dev->slave_writing = 0; + if (dev->slave_rw) { + dev->slave_state = SLAVE_SENDDATA; + dev->transmit = TRANSMITTER_SLAVE; + dev->byte = i2c_read_byte(dev->i2c, dev->slave_addr); + } else { + dev->slave_state = SLAVE_RECEIVEADDR; + dev->transmit = TRANSMITTER_MASTER; + } + pclog("slave_idle %02X %d\n", dev->slave_addr, dev->slave_rw); + break; + + case SLAVE_RECEIVEADDR: + pclog("slave_receiveaddr %02X %d\n", dev->slave_addr, dev->slave_rw); + i2c_write_byte(dev->i2c, dev->slave_addr, dev->byte); + dev->slave_writing = 1; + dev->slave_reg = dev->byte; + dev->slave_state = dev->slave_rw ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA; + break; + + case SLAVE_RECEIVEDATA: + pclog("slave_receivedata %02X %d = %02X\n", dev->slave_addr, dev->slave_rw, dev->byte); + dev->slave_writing = 0; + i2c_write_byte_cmd(dev->i2c, dev->slave_addr, dev->slave_reg, dev->byte); + break; + + case SLAVE_SENDDATA: + pclog("slave_senddata %02X %d = %02X\n", dev->slave_addr, dev->slave_rw, dev->byte); + break; + } +} + + +void +i2c_gpio_stop(i2c_gpio_t *dev) +{ + pclog("stopping... state = %d\n", dev->slave_state); + if (dev->slave_writing) + i2c_write_byte(dev->i2c, dev->slave_addr, dev->slave_reg); + + dev->slave_state = SLAVE_IDLE; + dev->transmit = TRANSMITTER_MASTER; +} + + +void +i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) +{ + i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; + + switch (dev->state) { + case I2C_IDLE: + if (dev->scl && scl && dev->last_sda && !sda) { /* start bit */ + dev->state = I2C_RECEIVE; + dev->pos = 0; + } + break; + + case I2C_RECEIVE_WAIT: + if (!dev->scl && scl) + dev->state = I2C_RECEIVE; + /* fall-through */ + + case I2C_RECEIVE: + if (!dev->scl && scl) { + dev->byte <<= 1; + if (sda) + dev->byte |= 1; + else + dev->byte &= 0xfe; + if (++dev->pos == 8) { + i2c_gpio_write(dev); + dev->state = I2C_ACKNOWLEDGE; + } + } else if (dev->scl && scl) { + if (sda && !dev->last_sda) { /* stop bit */ + dev->state = I2C_IDLE; + i2c_gpio_stop(dev); + } else if (!sda && dev->last_sda) { /* start bit */ + dev->pos = 0; + dev->slave_state = SLAVE_IDLE; + } + } + break; + + case I2C_ACKNOWLEDGE: + if (!dev->scl && scl) { + sda = 0; + dev->pos = 0; + dev->state = (dev->transmit == TRANSMITTER_MASTER) ? I2C_RECEIVE_WAIT : I2C_TRANSMIT; + } + break; + + case I2C_TRANSACKNOWLEDGE: + if (!dev->scl && scl) { + if (sda) { /* not acknowledged; must be end of transfer */ + dev->state = I2C_IDLE; + i2c_gpio_stop(dev); + } else { /* next byte to transfer */ + dev->state = I2C_TRANSMIT_START; + i2c_gpio_next_byte(dev); + dev->pos = 0; + } + } + break; + + case I2C_TRANSMIT_WAIT: + if (dev->scl && scl) { + if (dev->last_sda && !sda) { /* start bit */ + i2c_gpio_next_byte(dev); + dev->pos = 0; + } + if (!dev->last_sda && sda) { /* stop bit */ + dev->state = I2C_IDLE; + i2c_gpio_stop(dev); + } + } + break; + + case I2C_TRANSMIT_START: + if (!dev->scl && scl) + dev->state = I2C_TRANSMIT; + if (dev->scl && scl && !dev->last_sda && sda) { /* stop bit */ + dev->state = I2C_IDLE; + i2c_gpio_stop(dev); + } + /* fall-through */ + + case I2C_TRANSMIT: + if (!dev->scl && scl) { + dev->scl = scl; + dev->sda = sda = dev->byte & 0x80; + dev->byte <<= 1; + dev->pos++; + return; + } + if (dev->scl && !scl && (dev->pos == 8)) + dev->state = I2C_TRANSACKNOWLEDGE; + break; + } + + if (!dev->scl && scl) + dev->sda = sda; + dev->last_sda = sda; + dev->scl = scl; +} + + +uint8_t +i2c_gpio_get_scl(void *dev_handle) +{ + i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; + return dev->scl; +} + + +uint8_t +i2c_gpio_get_sda(void *dev_handle) +{ + i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; + if ((dev->state == I2C_TRANSMIT) || (dev->state == I2C_ACKNOWLEDGE)) + return dev->sda; + else if (dev->state == I2C_RECEIVE_WAIT) + return 0; /* ack */ + else + return 1; +} + + +void * +i2c_gpio_get_bus(void *dev_handle) +{ + i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; + return dev->i2c; +} diff --git a/src/device/smbus.c b/src/device/smbus.c deleted file mode 100644 index dfd89a95e..000000000 --- a/src/device/smbus.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implement SMBus (System Management Bus) and its operations. - * - * - * - * Authors: RichardG, - * - * Copyright 2020 RichardG. - */ -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/smbus.h> - - -#define NADDRS 128 /* SMBus supports 128 addresses */ -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - - -typedef struct _smbus_ { - uint8_t (*read_byte)(uint8_t addr, void *priv); - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv); - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv); - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv); - - void (*write_byte)(uint8_t addr, uint8_t val, void *priv); - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv); - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv); - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv); - - void *priv; - - struct _smbus_ *prev, *next; -} smbus_t; - -int smbus_initialized = 0; -smbus_t *smbus[NADDRS], *smbus_last[NADDRS]; - - -#ifdef ENABLE_SMBUS_LOG -int smbus_do_log = ENABLE_SMBUS_LOG; - - -static void -smbus_log(const char *fmt, ...) -{ - va_list ap; - - if (smbus_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define smbus_log(fmt, ...) -#endif - - -void -smbus_init(void) -{ - int c; - smbus_t *p, *q; - - if (!smbus_initialized) { - for (c=0; cprev; - free(p); - p = q; - } - p = NULL; - } - - /* smbus[c] should be NULL. */ - smbus[c] = smbus_last[c] = NULL; - } -} - - -void -smbus_sethandler(uint8_t base, int size, - uint8_t (*read_byte)(uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_byte)(uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void *priv) -{ - int c; - smbus_t *p, *q = NULL; - - if ((base + size) >= NADDRS) - return; - - for (c = 0; c < size; c++) { - p = smbus_last[base + c]; - q = (smbus_t *) malloc(sizeof(smbus_t)); - memset(q, 0, sizeof(smbus_t)); - if (p) { - p->next = q; - q->prev = p; - } else { - smbus[base + c] = q; - q->prev = NULL; - } - - q->read_byte = read_byte; - q->read_byte_cmd = read_byte_cmd; - q->read_word_cmd = read_word_cmd; - q->read_block_cmd = read_block_cmd; - - q->write_byte = write_byte; - q->write_byte_cmd = write_byte_cmd; - q->write_word_cmd = write_word_cmd; - q->write_block_cmd = write_block_cmd; - - q->priv = priv; - q->next = NULL; - - smbus_last[base + c] = q; - } -} - - -void -smbus_removehandler(uint8_t base, int size, - uint8_t (*read_byte)(uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_byte)(uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void *priv) -{ - int c; - smbus_t *p, *q; - - if ((base + size) >= NADDRS) - return; - - for (c = 0; c < size; c++) { - p = smbus[base + c]; - if (!p) - continue; - while(p) { - q = p->next; - if ((p->read_byte == read_byte) && (p->read_byte_cmd == read_byte_cmd) && - (p->read_word_cmd == read_word_cmd) && (p->read_block_cmd == read_block_cmd) && - (p->write_byte == write_byte) && (p->write_byte_cmd == write_byte_cmd) && - (p->write_word_cmd == write_word_cmd) && (p->write_block_cmd == write_block_cmd) && - (p->priv == priv)) { - if (p->prev) - p->prev->next = p->next; - else - smbus[base + c] = p->next; - if (p->next) - p->next->prev = p->prev; - else - smbus_last[base + c] = p->prev; - free(p); - p = NULL; - break; - } - p = q; - } - } -} - - -void -smbus_handler(int set, uint8_t base, int size, - uint8_t (*read_byte)(uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_byte)(uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void *priv) -{ - if (set) - smbus_sethandler(base, size, read_byte, read_byte_cmd, read_word_cmd, read_block_cmd, write_byte, write_byte_cmd, write_word_cmd, write_block_cmd, priv); - else - smbus_removehandler(base, size, read_byte, read_byte_cmd, read_word_cmd, read_block_cmd, write_byte, write_byte_cmd, write_word_cmd, write_block_cmd, priv); -} - - -uint8_t -smbus_has_device(uint8_t addr) -{ - return(!!smbus[addr]); -} - - -uint8_t -smbus_read_byte(uint8_t addr) -{ - uint8_t ret = 0xff; - smbus_t *p; - int found = 0; - - p = smbus[addr]; - if (p) { - while(p) { - if (p->read_byte) { - ret &= p->read_byte(addr, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: read_byte(%02X) = %02X\n", addr, ret); - - return(ret); -} - -uint8_t -smbus_read_byte_cmd(uint8_t addr, uint8_t cmd) -{ - uint8_t ret = 0xff; - smbus_t *p; - int found = 0; - - p = smbus[addr]; - if (p) { - while(p) { - if (p->read_byte_cmd) { - ret &= p->read_byte_cmd(addr, cmd, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: read_byte_cmd(%02X, %02X) = %02X\n", addr, cmd, ret); - - return(ret); -} - -uint16_t -smbus_read_word_cmd(uint8_t addr, uint8_t cmd) -{ - uint16_t ret = 0xffff; - smbus_t *p; - int found = 0; - - p = smbus[addr]; - if (p) { - while(p) { - if (p->read_word_cmd) { - ret &= p->read_word_cmd(addr, cmd, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: read_word_cmd(%02X, %02X) = %04X\n", addr, cmd, ret); - - return(ret); -} - -uint8_t -smbus_read_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len) -{ - uint8_t ret = 0; - smbus_t *p; - int found = 0; - - p = smbus[addr]; - if (p) { - while(p) { - if (p->read_block_cmd) { - ret = MAX(ret, p->read_block_cmd(addr, cmd, data, len, p->priv)); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: read_block_cmd(%02X, %02X) = %02X\n", addr, cmd, len); - - return(ret); -} - - -void -smbus_write_byte(uint8_t addr, uint8_t val) -{ - smbus_t *p; - int found = 0; - - if (smbus[addr]) { - p = smbus[addr]; - while(p) { - if (p->write_byte) { - p->write_byte(addr, val, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: write_byte(%02X, %02X)\n", addr, val); - - return; -} - -void -smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val) -{ - smbus_t *p; - int found = 0; - - if (smbus[addr]) { - p = smbus[addr]; - while(p) { - if (p->write_byte_cmd) { - p->write_byte_cmd(addr, cmd, val, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: write_byte_cmd(%02X, %02X, %02X)\n", addr, cmd, val); - - return; -} - -void -smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val) -{ - smbus_t *p; - int found = 0; - - if (smbus[addr]) { - p = smbus[addr]; - while(p) { - if (p->write_word_cmd) { - p->write_word_cmd(addr, cmd, val, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: write_word_cmd(%02X, %02X, %04X)\n", addr, cmd, val); - - return; -} - -void -smbus_write_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len) -{ - smbus_t *p; - int found = 0; - - p = smbus[addr]; - if (p) { - while(p) { - if (p->write_block_cmd) { - p->write_block_cmd(addr, cmd, data, len, p->priv); - found++; - } - p = p->next; - } - } - - smbus_log("SMBus: write_block_cmd(%02X, %02X, %02X)\n", addr, cmd, len); - - return; -} diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index f9b68f6d8..e8cd32eb2 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -25,7 +25,7 @@ #include <86box/io.h> #include <86box/device.h> #include <86box/timer.h> -#include <86box/smbus.h> +#include <86box/i2c.h> #include <86box/smbus_piix4.h> @@ -59,22 +59,28 @@ smbus_piix4_read(uint16_t addr, void *priv) case 0x00: ret = dev->stat; break; + case 0x02: dev->index = 0; /* reading from this resets the block data index */ ret = dev->ctl; break; + case 0x03: ret = dev->cmd; break; + case 0x04: ret = dev->addr; break; + case 0x05: ret = dev->data0; break; + case 0x06: ret = dev->data1; break; + case 0x07: ret = dev->data[dev->index++]; if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE) @@ -82,7 +88,7 @@ smbus_piix4_read(uint16_t addr, void *priv) break; } - smbus_piix4_log("SMBus PIIX4: read(%02x) = %02x\n", addr, ret); + smbus_piix4_log("SMBus PIIX4: read(%02X) = %02x\n", addr, ret); return ret; } @@ -95,7 +101,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) uint8_t smbus_addr, smbus_read, prev_stat; uint16_t temp; - smbus_piix4_log("SMBus PIIX4: write(%02x, %02x)\n", addr, val); + smbus_piix4_log("SMBus PIIX4: write(%02X, %02X)\n", addr, val); prev_stat = dev->next_stat; dev->next_stat = 0; @@ -107,6 +113,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) dev->stat &= ~smbus_addr; } break; + case 0x02: dev->ctl = val & ~(0x40); /* START always reads 0 */ if (val & 0x02) { /* cancel an in-progress command if KILL is set */ @@ -118,49 +125,53 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) } if (val & 0x40) { /* dispatch command if START is set */ smbus_addr = (dev->addr >> 1); - if (!smbus_has_device(smbus_addr)) { + if (!i2c_has_device(i2c_smbus, smbus_addr)) { /* raise DEV_ERR if no device is at this address */ dev->next_stat = 0x4; break; } - smbus_read = (dev->addr & 0x01); + smbus_read = dev->addr & 0x01; /* decode the 3-bit command protocol */ dev->next_stat = 0x2; /* raise INTER (command completed) by default */ switch ((val >> 2) & 0x7) { case 0x0: /* quick R/W */ + if (smbus_read) + i2c_read_quick(i2c_smbus, smbus_addr); + else + i2c_write_quick(i2c_smbus, smbus_addr); break; case 0x1: /* byte R/W */ if (smbus_read) - dev->data0 = smbus_read_byte(smbus_addr); + dev->data0 = i2c_read_byte(i2c_smbus, smbus_addr); else - smbus_write_byte(smbus_addr, dev->data0); + i2c_write_byte(i2c_smbus, smbus_addr, dev->data0); break; case 0x2: /* byte data R/W */ if (smbus_read) - dev->data0 = smbus_read_byte_cmd(smbus_addr, dev->cmd); + dev->data0 = i2c_read_byte_cmd(i2c_smbus, smbus_addr, dev->cmd); else - smbus_write_byte_cmd(smbus_addr, dev->cmd, dev->data0); + i2c_write_byte_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data0); break; case 0x3: /* word data R/W */ if (smbus_read) { - temp = smbus_read_word_cmd(smbus_addr, dev->cmd); - dev->data0 = (temp & 0xFF); - dev->data1 = (temp >> 8); + temp = i2c_read_word_cmd(i2c_smbus, smbus_addr, dev->cmd); + dev->data0 = temp; + dev->data1 = temp >> 8; } else { - temp = ((dev->data1 << 8) | dev->data0); - smbus_write_word_cmd(smbus_addr, dev->cmd, temp); + temp = (dev->data1 << 8) | dev->data0; + i2c_write_word_cmd(i2c_smbus, smbus_addr, dev->cmd, temp); } break; case 0x5: /* block R/W */ if (smbus_read) - dev->data0 = smbus_read_block_cmd(smbus_addr, dev->cmd, dev->data, SMBUS_PIIX4_BLOCK_DATA_SIZE); + dev->data0 = i2c_read_block_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data, SMBUS_PIIX4_BLOCK_DATA_SIZE); else - smbus_write_block_cmd(smbus_addr, dev->cmd, dev->data, dev->data0); + i2c_write_block_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data, dev->data0); break; default: @@ -170,18 +181,23 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) } } break; + case 0x03: dev->cmd = val; break; + case 0x04: dev->addr = val; break; + case 0x05: dev->data0 = val; break; + case 0x06: dev->data1 = val; break; + case 0x07: dev->data[dev->index++] = val; if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE) @@ -189,7 +205,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) break; } - /* if a status register update was given, dispatch it after 10ms to ensure nothing breaks */ + /* if a status register update was given, dispatch it after 10us to ensure nothing breaks */ if (dev->next_stat) { dev->stat = 0x1; /* raise HOST_BUSY while waiting */ timer_disable(&dev->response_timer); @@ -228,7 +244,8 @@ smbus_piix4_init(const device_t *info) smbus_piix4_t *dev = (smbus_piix4_t *) malloc(sizeof(smbus_piix4_t)); memset(dev, 0, sizeof(smbus_piix4_t)); - smbus_init(); + i2c_smbus = i2c_addbus("smbus_piix4"); + timer_add(&dev->response_timer, smbus_piix4_response, dev, 0); return dev; @@ -240,6 +257,9 @@ smbus_piix4_close(void *priv) { smbus_piix4_t *dev = (smbus_piix4_t *) priv; + i2c_removebus(i2c_smbus); + i2c_smbus = NULL; + free(dev); } diff --git a/src/include/86box/hwm.h b/src/include/86box/hwm.h index 27cb4a921..d77437bde 100644 --- a/src/include/86box/hwm.h +++ b/src/include/86box/hwm.h @@ -35,9 +35,9 @@ typedef struct { uint8_t regs[8]; uint8_t addr_register; uint8_t temp_idx; - uint8_t smbus_addr; + uint8_t i2c_addr; - uint8_t as99127f_smbus_addr; + uint8_t as99127f_i2c_addr; } lm75_t; diff --git a/src/include/86box/i2c.h b/src/include/86box/i2c.h new file mode 100644 index 000000000..5c94f766e --- /dev/null +++ b/src/include/86box/i2c.h @@ -0,0 +1,89 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the I2C handler. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#ifndef EMU_I2C_H +# define EMU_I2C_H + + +/* i2c.c */ +extern void *i2c_smbus; + + +/* i2c.c */ +extern void *i2c_addbus(char *name); +extern void i2c_removebus(void *bus_handle); + +extern void i2c_sethandler(void *bus_handle, uint8_t base, int size, + void (*read_quick)(void *bus, uint8_t addr, void *priv), + uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv), + uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), + uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), + uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void (*write_quick)(void *bus, uint8_t addr, void *priv), + void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv), + void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv), + void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv), + void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void *priv); + +extern void i2c_removehandler(void *bus_handle, uint8_t base, int size, + void (*read_quick)(void *bus, uint8_t addr, void *priv), + uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv), + uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), + uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), + uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void (*write_quick)(void *bus, uint8_t addr, void *priv), + void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv), + void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv), + void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv), + void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void *priv); + +extern void i2c_handler(int set, void *bus_handle, uint8_t base, int size, + void (*read_quick)(void *bus, uint8_t addr, void *priv), + uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv), + uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), + uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), + uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void (*write_quick)(void *bus, uint8_t addr, void *priv), + void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv), + void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv), + void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv), + void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void *priv); + +extern uint8_t i2c_has_device(void *bus_handle, uint8_t addr); +extern void i2c_read_quick(void *bus_handle, uint8_t addr); +extern uint8_t i2c_read_byte(void *bus_handle, uint8_t addr); +extern uint8_t i2c_read_byte_cmd(void *bus_handle, uint8_t addr, uint8_t cmd); +extern uint16_t i2c_read_word_cmd(void *bus_handle, uint8_t addr, uint8_t cmd); +extern uint8_t i2c_read_block_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len); +extern void i2c_write_quick(void *bus_handle, uint8_t addr); +extern void i2c_write_byte(void *bus_handle, uint8_t addr, uint8_t val); +extern void i2c_write_byte_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t val); +extern void i2c_write_word_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint16_t val); +extern void i2c_write_block_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len); + +/* i2c_gpio.c */ +extern void *i2c_gpio_init(char *bus_name); +extern void i2c_gpio_close(void *dev_handle); +extern void i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda); +extern uint8_t i2c_gpio_get_scl(void *dev_handle); +extern uint8_t i2c_gpio_get_sda(void *dev_handle); +extern void *i2c_gpio_get_bus(); + + +#endif /*EMU_I2C_H*/ diff --git a/src/include/86box/smbus.h b/src/include/86box/smbus.h deleted file mode 100644 index 6923a7edb..000000000 --- a/src/include/86box/smbus.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Definitions for the SMBus handler. - * - * - * - * Authors: RichardG, - * - * Copyright 2020 RichardG. - */ -#ifndef EMU_SMBUS_H -# define EMU_SMBUS_H - - -extern void smbus_init(void); - -extern void smbus_sethandler(uint8_t base, int size, - uint8_t (*read_byte)(uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_byte)(uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void *priv); - -extern void smbus_removehandler(uint8_t base, int size, - uint8_t (*read_byte)(uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_byte)(uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void *priv); - -extern void smbus_handler(int set, uint8_t base, int size, - uint8_t (*read_byte)(uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_byte)(uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void *priv); - -extern uint8_t smbus_has_device(uint8_t addr); -extern uint8_t smbus_read_byte(uint8_t addr); -extern uint8_t smbus_read_byte_cmd(uint8_t addr, uint8_t cmd); -extern uint16_t smbus_read_word_cmd(uint8_t addr, uint8_t cmd); -extern uint8_t smbus_read_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len); -extern void smbus_write_byte(uint8_t addr, uint8_t val); -extern void smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val); -extern void smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val); -extern void smbus_write_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len); - - -#endif /*EMU_SMBUS_H*/ diff --git a/src/include/86box/vid_ddc.h b/src/include/86box/vid_ddc.h index 7b8f8bd29..b2f3e50e9 100644 --- a/src/include/86box/vid_ddc.h +++ b/src/include/86box/vid_ddc.h @@ -1,4 +1,24 @@ -void ddc_init(void); -void ddc_i2c_change(int new_clock, int new_data); -int ddc_read_clock(void); -int ddc_read_data(void); +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * DDC monitor emulation definitions. + * + * + * + * Authors: Sarah Walker, + * RichardG, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2020 RichardG. + */ +#ifndef EMU_VID_DDC_H +# define EMU_VID_DDC_H + +extern void ddc_init(void *i2c); + +#endif /*EMU_VID_DDC_H*/ diff --git a/src/mem/spd.c b/src/mem/spd.c index 0268c1d5a..9f1285754 100644 --- a/src/mem/spd.c +++ b/src/mem/spd.c @@ -23,7 +23,7 @@ #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> -#include <86box/smbus.h> +#include <86box/i2c.h> #include <86box/spd.h> #include <86box/version.h> #include <86box/machine.h> @@ -37,11 +37,6 @@ spd_t *spd_devices[SPD_MAX_SLOTS]; uint8_t spd_data[SPD_MAX_SLOTS][SPD_DATA_SIZE]; -static uint8_t spd_read_byte(uint8_t addr, void *priv); -static uint8_t spd_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv); -static void spd_write_byte(uint8_t addr, uint8_t val, void *priv); - - #ifdef ENABLE_SPD_LOG int spd_do_log = ENABLE_SPD_LOG; @@ -52,9 +47,9 @@ spd_log(const char *fmt, ...) va_list ap; if (spd_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); } } #else @@ -63,15 +58,7 @@ spd_log(const char *fmt, ...) uint8_t -spd_read_byte(uint8_t addr, void *priv) -{ - spd_t *dev = (spd_t *) priv; - return spd_read_byte_cmd(addr, dev->addr_register, priv); -} - - -uint8_t -spd_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) +spd_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) { spd_t *dev = (spd_t *) priv; uint8_t ret = *(spd_data[dev->slot] + cmd); @@ -80,26 +67,33 @@ spd_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv) } -uint16_t -spd_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv) +uint8_t +spd_read_byte(void *bus, uint8_t addr, void *priv) { - return (spd_read_byte_cmd(addr, cmd + 1, priv) << 8) | spd_read_byte_cmd(addr, cmd, priv); + spd_t *dev = (spd_t *) priv; + return spd_read_byte_cmd(bus, addr, dev->addr_register, priv); +} + + +uint16_t +spd_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) +{ + return (spd_read_byte_cmd(bus, addr, cmd + 1, priv) << 8) | spd_read_byte_cmd(bus, addr, cmd, priv); } uint8_t -spd_read_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv) +spd_read_block_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv) { uint8_t read = 0; - for (uint8_t i = cmd; i < len && i < SPD_DATA_SIZE; i++) { - data[read++] = spd_read_byte_cmd(addr, i, priv); - } + for (uint8_t i = cmd; (i < len) && (i < SPD_DATA_SIZE); i++) + data[read++] = spd_read_byte_cmd(bus, addr, i, priv); return read; } void -spd_write_byte(uint8_t addr, uint8_t val, void *priv) +spd_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv) { spd_t *dev = (spd_t *) priv; dev->addr_register = val; @@ -111,12 +105,12 @@ spd_close(void *priv) { spd_t *dev = (spd_t *) priv; - spd_log("SPD: closing slot %d (SMBus %02Xh)\n", dev->slot, SPD_BASE_ADDR + dev->slot); + spd_log("SPD: closing slot %d (SMBus %02X)\n", dev->slot, SPD_BASE_ADDR + dev->slot); - smbus_removehandler(SPD_BASE_ADDR + dev->slot, 1, - spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd, - spd_write_byte, NULL, NULL, NULL, - dev); + i2c_removehandler(i2c_smbus, SPD_BASE_ADDR + dev->slot, 1, + NULL, spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd, + NULL, spd_write_byte, NULL, NULL, NULL, + dev); spd_present = 0; @@ -129,12 +123,12 @@ spd_init(const device_t *info) { spd_t *dev = spd_devices[info->local]; - spd_log("SPD: initializing slot %d (SMBus %02Xh)\n", dev->slot, SPD_BASE_ADDR + dev->slot); + spd_log("SPD: initializing slot %d (SMBus %02X)\n", dev->slot, SPD_BASE_ADDR + dev->slot); - smbus_sethandler(SPD_BASE_ADDR + dev->slot, 1, - spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd, - spd_write_byte, NULL, NULL, NULL, - dev); + i2c_sethandler(i2c_smbus, SPD_BASE_ADDR + dev->slot, 1, + NULL, spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd, + NULL, spd_write_byte, NULL, NULL, NULL, + dev); spd_present = 1; @@ -147,7 +141,7 @@ log2_ui16(uint16_t i) { uint8_t ret = 0; while ((i >>= 1)) - ret++; + ret++; return ret; } @@ -170,63 +164,63 @@ spd_populate(uint16_t *vslots, uint8_t slot_count, uint16_t total_size, uint16_t /* populate vslots with modules in power-of-2 capacities */ memset(vslots, 0x00, SPD_MAX_SLOTS << 1); for (vslot = 0; vslot < slot_count && total_size; vslot++) { - /* populate slot */ - vslots[vslot] = (1 << log2_ui16(MIN(total_size, max_module_size))); - if (total_size >= vslots[vslot]) { - spd_log("SPD: initial vslot %d = %d MB\n", vslot, vslots[vslot]); - total_size -= vslots[vslot]; - } else { - vslots[vslot] = 0; - break; - } + /* populate slot */ + vslots[vslot] = 1 << log2_ui16(MIN(total_size, max_module_size)); + if (total_size >= vslots[vslot]) { + spd_log("SPD: initial vslot %d = %d MB\n", vslot, vslots[vslot]); + total_size -= vslots[vslot]; + } else { + vslots[vslot] = 0; + break; + } } /* did we populate all the RAM? */ if (total_size) { - /* work backwards to add the missing RAM as asymmetric modules if possible */ - if (enable_asym) { - vslot = slot_count - 1; - do { - asym = (1 << log2_ui16(MIN(total_size, vslots[vslot]))); - if (vslots[vslot] + asym <= max_module_size) { - vslots[vslot] += asym; - total_size -= asym; - } - } while ((vslot-- > 0) && total_size); - } + /* work backwards to add the missing RAM as asymmetric modules if possible */ + if (enable_asym) { + vslot = slot_count - 1; + do { + asym = (1 << log2_ui16(MIN(total_size, vslots[vslot]))); + if (vslots[vslot] + asym <= max_module_size) { + vslots[vslot] += asym; + total_size -= asym; + } + } while ((vslot-- > 0) && total_size); + } - if (total_size) /* still not enough */ - spd_log("SPD: not enough RAM slots (%d) to cover memory (%d MB short)\n", slot_count, total_size); + if (total_size) /* still not enough */ + spd_log("SPD: not enough RAM slots (%d) to cover memory (%d MB short)\n", slot_count, total_size); } /* populate empty vslots by splitting modules... */ split = (total_size == 0); /* ...if possible */ while (split) { - /* look for a module to split */ - split = 0; - for (vslot = 0; vslot < slot_count; vslot++) { - if ((vslots[vslot] < (min_module_size << 1)) || (vslots[vslot] != (1 << log2_ui16(vslots[vslot])))) - continue; /* no module here, module is too small to be split, or asymmetric module */ + /* look for a module to split */ + split = 0; + for (vslot = 0; vslot < slot_count; vslot++) { + if ((vslots[vslot] < (min_module_size << 1)) || (vslots[vslot] != (1 << log2_ui16(vslots[vslot])))) + continue; /* no module here, module is too small to be split, or asymmetric module */ - /* find next empty vslot */ - next_empty_vslot = 0; - for (i = vslot + 1; i < slot_count && !next_empty_vslot; i++) { - if (!vslots[i]) - next_empty_vslot = i; - } - if (!next_empty_vslot) - break; /* no empty vslots left */ + /* find next empty vslot */ + next_empty_vslot = 0; + for (i = vslot + 1; i < slot_count && !next_empty_vslot; i++) { + if (!vslots[i]) + next_empty_vslot = i; + } + if (!next_empty_vslot) + break; /* no empty vslots left */ - /* split the module into its own vslot and the next empty vslot */ - spd_log("SPD: splitting vslot %d (%d MB) into %d and %d (%d MB each)\n", vslot, vslots[vslot], vslot, next_empty_vslot, (vslots[vslot] >> 1)); - vslots[vslot] = vslots[next_empty_vslot] = (vslots[vslot] >> 1); - split = 1; - break; - } + /* split the module into its own vslot and the next empty vslot */ + spd_log("SPD: splitting vslot %d (%d MB) into %d and %d (%d MB each)\n", vslot, vslots[vslot], vslot, next_empty_vslot, vslots[vslot] >> 1); + vslots[vslot] = vslots[next_empty_vslot] = vslots[vslot] >> 1; + split = 1; + break; + } - /* sort vslots by descending capacity if any were split */ - if (split) - qsort(vslots, slot_count, sizeof(uint16_t), comp_ui16_rev); + /* sort vslots by descending capacity if any were split */ + if (split) + qsort(vslots, slot_count, sizeof(uint16_t), comp_ui16_rev); } } @@ -242,27 +236,27 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) /* determine the minimum module size for this RAM type */ switch (ram_type) { - case SPD_TYPE_FPM: - case SPD_TYPE_EDO: - min_module_size = SPD_MIN_SIZE_EDO; - break; + case SPD_TYPE_FPM: + case SPD_TYPE_EDO: + min_module_size = SPD_MIN_SIZE_EDO; + break; - case SPD_TYPE_SDRAM: - min_module_size = SPD_MIN_SIZE_SDRAM; - break; + case SPD_TYPE_SDRAM: + min_module_size = SPD_MIN_SIZE_SDRAM; + break; default: - spd_log("SPD: unknown RAM type 0x%02X\n", ram_type); - return; + spd_log("SPD: unknown RAM type %02X\n", ram_type); + return; } /* count how many (real) slots are enabled */ slot_count = 0; for (slot = 0; slot < SPD_MAX_SLOTS; slot++) { - vslots[slot] = 0; - if (slot_mask & (1 << slot)) { - slot_count++; - } + vslots[slot] = 0; + if (slot_mask & (1 << slot)) { + slot_count++; + } } /* populate vslots */ @@ -271,134 +265,134 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) /* register SPD devices and populate their data according to the vslots */ vslot = 0; for (slot = 0; slot < SPD_MAX_SLOTS && vslots[vslot]; slot++) { - if (!(slot_mask & (1 << slot))) - continue; /* slot disabled */ + if (!(slot_mask & (1 << slot))) + continue; /* slot disabled */ - info = (device_t *) malloc(sizeof(device_t)); - memset(info, 0, sizeof(device_t)); - info->name = "Serial Presence Detect ROM"; - info->local = slot; - info->init = spd_init; - info->close = spd_close; + info = (device_t *) malloc(sizeof(device_t)); + memset(info, 0, sizeof(device_t)); + info->name = "Serial Presence Detect ROM"; + info->local = slot; + info->init = spd_init; + info->close = spd_close; - spd_devices[slot] = (spd_t *) malloc(sizeof(spd_t)); - memset(spd_devices[slot], 0, sizeof(spd_t)); - spd_devices[slot]->info = info; - spd_devices[slot]->slot = slot; - spd_devices[slot]->size = vslots[vslot]; + spd_devices[slot] = (spd_t *) malloc(sizeof(spd_t)); + memset(spd_devices[slot], 0, sizeof(spd_t)); + spd_devices[slot]->info = info; + spd_devices[slot]->slot = slot; + spd_devices[slot]->size = vslots[vslot]; - /* determine the second row size, from which the first row size can be obtained */ - asym = (vslots[vslot] - (1 << log2_ui16(vslots[vslot]))); /* separate the powers of 2 */ - if (!asym) /* is the module asymmetric? */ - asym = (vslots[vslot] >> 1); /* symmetric, therefore divide by 2 */ + /* determine the second row size, from which the first row size can be obtained */ + asym = vslots[vslot] - (1 << log2_ui16(vslots[vslot])); /* separate the powers of 2 */ + if (!asym) /* is the module asymmetric? */ + asym = vslots[vslot] >> 1; /* symmetric, therefore divide by 2 */ - spd_devices[slot]->row1 = (vslots[vslot] - asym); - spd_devices[slot]->row2 = asym; + spd_devices[slot]->row1 = vslots[vslot] - asym; + spd_devices[slot]->row2 = asym; - spd_log("SPD: registering slot %d = vslot %d = %d MB (%d/%d)\n", slot, vslot, vslots[vslot], spd_devices[slot]->row1, spd_devices[slot]->row2); + spd_log("SPD: registering slot %d = vslot %d = %d MB (%d/%d)\n", slot, vslot, vslots[vslot], spd_devices[slot]->row1, spd_devices[slot]->row2); - switch (ram_type) { - case SPD_TYPE_FPM: - case SPD_TYPE_EDO: - edo_data = (spd_edo_t *) &spd_data[slot]; - memset(edo_data, 0, sizeof(spd_edo_t)); + switch (ram_type) { + case SPD_TYPE_FPM: + case SPD_TYPE_EDO: + edo_data = (spd_edo_t *) &spd_data[slot]; + memset(edo_data, 0, sizeof(spd_edo_t)); - /* EDO SPD is specified by JEDEC and present in some modules, but - most utilities cannot interpret it correctly. SIV32 at least gets - the module capacities right, so it was used as a reference here. */ - edo_data->bytes_used = 0x80; - edo_data->spd_size = 0x08; - edo_data->mem_type = ram_type; - edo_data->row_bits = SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row1)); /* first row */ - edo_data->col_bits = 9; - if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ - edo_data->row_bits |= (SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row2)) << 4); /* second row, if different from first */ - edo_data->col_bits |= (9 << 4); /* same as first row, but just in case */ - } - edo_data->banks = 2; - edo_data->data_width_lsb = 64; - edo_data->signal_level = SPD_SIGNAL_LVTTL; - edo_data->trac = 50; - edo_data->tcac = 13; - edo_data->refresh_rate = SPD_REFRESH_NORMAL; - edo_data->dram_width = 8; + /* EDO SPD is specified by JEDEC and present in some modules, but + most utilities cannot interpret it correctly. SIV32 at least gets + the module capacities right, so it was used as a reference here. */ + edo_data->bytes_used = 0x80; + edo_data->spd_size = 0x08; + edo_data->mem_type = ram_type; + edo_data->row_bits = SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row1)); /* first row */ + edo_data->col_bits = 9; + if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ + edo_data->row_bits |= SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row2)) << 4; /* second row, if different from first */ + edo_data->col_bits |= 9 << 4; /* same as first row, but just in case */ + } + edo_data->banks = 2; + edo_data->data_width_lsb = 64; + edo_data->signal_level = SPD_SIGNAL_LVTTL; + edo_data->trac = 50; + edo_data->tcac = 13; + edo_data->refresh_rate = SPD_REFRESH_NORMAL; + edo_data->dram_width = 8; - edo_data->spd_rev = 0x12; - sprintf(edo_data->part_no, EMU_NAME "-%s-%03dM", (ram_type == SPD_TYPE_FPM) ? "FPM" : "EDO", vslots[vslot]); - for (i = strlen(edo_data->part_no); i < sizeof(edo_data->part_no); i++) - edo_data->part_no[i] = ' '; /* part number should be space-padded */ - edo_data->rev_code[0] = BCD8(EMU_VERSION_MAJ); - edo_data->rev_code[1] = BCD8(EMU_VERSION_MIN); - edo_data->mfg_year = 20; - edo_data->mfg_week = 17; + edo_data->spd_rev = 0x12; + sprintf(edo_data->part_no, EMU_NAME "-%s-%03dM", (ram_type == SPD_TYPE_FPM) ? "FPM" : "EDO", vslots[vslot]); + for (i = strlen(edo_data->part_no); i < sizeof(edo_data->part_no); i++) + edo_data->part_no[i] = ' '; /* part number should be space-padded */ + edo_data->rev_code[0] = BCD8(EMU_VERSION_MAJ); + edo_data->rev_code[1] = BCD8(EMU_VERSION_MIN); + edo_data->mfg_year = 20; + edo_data->mfg_week = 17; - for (i = 0; i < 63; i++) - edo_data->checksum += spd_data[slot][i]; - for (i = 0; i < 129; i++) - edo_data->checksum2 += spd_data[slot][i]; - break; + for (i = 0; i < 63; i++) + edo_data->checksum += spd_data[slot][i]; + for (i = 0; i < 129; i++) + edo_data->checksum2 += spd_data[slot][i]; + break; - case SPD_TYPE_SDRAM: - sdram_data = (spd_sdram_t *) &spd_data[slot]; - memset(sdram_data, 0, sizeof(spd_sdram_t)); + case SPD_TYPE_SDRAM: + sdram_data = (spd_sdram_t *) &spd_data[slot]; + memset(sdram_data, 0, sizeof(spd_sdram_t)); - sdram_data->bytes_used = 0x80; - sdram_data->spd_size = 0x08; - sdram_data->mem_type = ram_type; - sdram_data->row_bits = SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row1)); /* first row */ - sdram_data->col_bits = 9; - if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ - sdram_data->row_bits |= (SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row2)) << 4); /* second row, if different from first */ - sdram_data->col_bits |= (9 << 4); /* same as first row, but just in case */ - } - sdram_data->rows = 2; - sdram_data->data_width_lsb = 64; - sdram_data->signal_level = SPD_SIGNAL_LVTTL; - sdram_data->tclk = 0x75; /* 7.5 ns = 133.3 MHz */ - sdram_data->tac = 0x10; - sdram_data->refresh_rate = SPD_SDR_REFRESH_SELF | SPD_REFRESH_NORMAL; - sdram_data->sdram_width = 8; - sdram_data->tccd = 1; - sdram_data->burst = SPD_SDR_BURST_PAGE | 1 | 2 | 4 | 8; - sdram_data->banks = 4; - sdram_data->cas = 0x1c; /* CAS 5/4/3 supported */ - sdram_data->cslat = sdram_data->we = 0x7f; - sdram_data->dev_attr = SPD_SDR_ATTR_EARLY_RAS | SPD_SDR_ATTR_AUTO_PC | SPD_SDR_ATTR_PC_ALL | SPD_SDR_ATTR_W1R_BURST; - sdram_data->tclk2 = 0xA0; /* 10 ns = 100 MHz */ - sdram_data->tclk3 = 0xF0; /* 15 ns = 66.7 MHz */ - sdram_data->tac2 = sdram_data->tac3 = 0x10; - sdram_data->trp = sdram_data->trrd = sdram_data->trcd = sdram_data->tras = 1; - if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { - /* Utilities interpret bank_density a bit differently on asymmetric modules. */ - sdram_data->bank_density = (1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 2)); /* first row */ - sdram_data->bank_density |= (1 << (log2_ui16(spd_devices[slot]->row2 >> 1) - 2)); /* second row */ - } else { - sdram_data->bank_density = (1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 1)); /* symmetric module = only one bit is set */ - } - sdram_data->ca_setup = sdram_data->data_setup = 0x15; - sdram_data->ca_hold = sdram_data->data_hold = 0x08; + sdram_data->bytes_used = 0x80; + sdram_data->spd_size = 0x08; + sdram_data->mem_type = ram_type; + sdram_data->row_bits = SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row1)); /* first row */ + sdram_data->col_bits = 9; + if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ + sdram_data->row_bits |= SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row2)) << 4; /* second row, if different from first */ + sdram_data->col_bits |= 9 << 4; /* same as first row, but just in case */ + } + sdram_data->rows = 2; + sdram_data->data_width_lsb = 64; + sdram_data->signal_level = SPD_SIGNAL_LVTTL; + sdram_data->tclk = 0x75; /* 7.5 ns = 133.3 MHz */ + sdram_data->tac = 0x10; + sdram_data->refresh_rate = SPD_SDR_REFRESH_SELF | SPD_REFRESH_NORMAL; + sdram_data->sdram_width = 8; + sdram_data->tccd = 1; + sdram_data->burst = SPD_SDR_BURST_PAGE | 1 | 2 | 4 | 8; + sdram_data->banks = 4; + sdram_data->cas = 0x1c; /* CAS 5/4/3 supported */ + sdram_data->cslat = sdram_data->we = 0x7f; + sdram_data->dev_attr = SPD_SDR_ATTR_EARLY_RAS | SPD_SDR_ATTR_AUTO_PC | SPD_SDR_ATTR_PC_ALL | SPD_SDR_ATTR_W1R_BURST; + sdram_data->tclk2 = 0xA0; /* 10 ns = 100 MHz */ + sdram_data->tclk3 = 0xF0; /* 15 ns = 66.7 MHz */ + sdram_data->tac2 = sdram_data->tac3 = 0x10; + sdram_data->trp = sdram_data->trrd = sdram_data->trcd = sdram_data->tras = 1; + if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { + /* Utilities interpret bank_density a bit differently on asymmetric modules. */ + sdram_data->bank_density = 1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 2); /* first row */ + sdram_data->bank_density |= 1 << (log2_ui16(spd_devices[slot]->row2 >> 1) - 2); /* second row */ + } else { + sdram_data->bank_density = 1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 1); /* symmetric module = only one bit is set */ + } + sdram_data->ca_setup = sdram_data->data_setup = 0x15; + sdram_data->ca_hold = sdram_data->data_hold = 0x08; - sdram_data->spd_rev = 0x12; - sprintf(sdram_data->part_no, EMU_NAME "-SDR-%03dM", vslots[vslot]); - for (i = strlen(sdram_data->part_no); i < sizeof(sdram_data->part_no); i++) - sdram_data->part_no[i] = ' '; /* part number should be space-padded */ - sdram_data->rev_code[0] = BCD8(EMU_VERSION_MAJ); - sdram_data->rev_code[1] = BCD8(EMU_VERSION_MIN); - sdram_data->mfg_year = 20; - sdram_data->mfg_week = 13; + sdram_data->spd_rev = 0x12; + sprintf(sdram_data->part_no, EMU_NAME "-SDR-%03dM", vslots[vslot]); + for (i = strlen(sdram_data->part_no); i < sizeof(sdram_data->part_no); i++) + sdram_data->part_no[i] = ' '; /* part number should be space-padded */ + sdram_data->rev_code[0] = BCD8(EMU_VERSION_MAJ); + sdram_data->rev_code[1] = BCD8(EMU_VERSION_MIN); + sdram_data->mfg_year = 20; + sdram_data->mfg_week = 13; - sdram_data->freq = 100; - sdram_data->features = 0xFF; + sdram_data->freq = 100; + sdram_data->features = 0xFF; - for (i = 0; i < 63; i++) - sdram_data->checksum += spd_data[slot][i]; - for (i = 0; i < 129; i++) - sdram_data->checksum2 += spd_data[slot][i]; - break; - } + for (i = 0; i < 63; i++) + sdram_data->checksum += spd_data[slot][i]; + for (i = 0; i < 129; i++) + sdram_data->checksum2 += spd_data[slot][i]; + break; + } - device_add(info); - vslot++; + device_add(info); + vslot++; } } @@ -411,49 +405,49 @@ spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit /* Special case for VIA Apollo Pro family, which jumps from 5F to 56. */ if (reg_max < reg_min) { - apollo = reg_max; - reg_max = reg_min + 7; + apollo = reg_max; + reg_max = reg_min + 7; } /* No SPD: split SIMMs into pairs as if they were "DIMM"s. */ if (!spd_present) { - dimm = ((reg_max - reg_min) + 1) >> 1; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */ - spd_populate(vslots, dimm, (mem_size >> 10), drb_unit, 1 << (log2_ui16(machines[machine].max_ram / dimm)), 0); + dimm = ((reg_max - reg_min) + 1) >> 1; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */ + spd_populate(vslots, dimm, mem_size >> 10, drb_unit, 1 << (log2_ui16(machines[machine].max_ram / dimm)), 0); } /* Write DRBs for each row. */ spd_log("Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit); for (row = 0; row <= (reg_max - reg_min); row++) { - dimm = (row >> 1); - size = 0; + dimm = (row >> 1); + size = 0; - if (spd_present) { - /* SPD enabled: use SPD info for this slot, if present. */ - if (spd_devices[dimm]) { - if (spd_devices[dimm]->row1 < drb_unit) /* hack within a hack: turn a double-sided DIMM that is too small into a single-sided one */ - size = ((row & 1) ? 0 : drb_unit); - else - size = ((row & 1) ? spd_devices[dimm]->row2 : spd_devices[dimm]->row1); - } - } else { - /* No SPD: use the values calculated above. */ - size = (vslots[dimm] >> 1); - } + if (spd_present) { + /* SPD enabled: use SPD info for this slot, if present. */ + if (spd_devices[dimm]) { + if (spd_devices[dimm]->row1 < drb_unit) /* hack within a hack: turn a double-sided DIMM that is too small into a single-sided one */ + size = (row & 1) ? 0 : drb_unit; + else + size = (row & 1) ? spd_devices[dimm]->row2 : spd_devices[dimm]->row1; + } + } else { + /* No SPD: use the values calculated above. */ + size = (vslots[dimm] >> 1); + } - /* Determine the DRB register to write. */ - drb = reg_min + row; - if ((apollo) && ((drb & 0xf) < 0xa)) - drb = apollo + (drb & 0xf); + /* Determine the DRB register to write. */ + drb = reg_min + row; + if (apollo && ((drb & 0xf) < 0xa)) + drb = apollo + (drb & 0xf); - /* Write DRB register, adding the previous DRB's value. */ - if (row == 0) - regs[drb] = 0; - else if ((apollo) && (drb == apollo)) - regs[drb] = regs[drb | 0xf]; /* 5F comes before 56 */ - else - regs[drb] = regs[drb - 1]; - if (size) - regs[drb] += (size / drb_unit); /* this will intentionally overflow on 440GX with 2 GB */ - spd_log("DRB[%d] = %d MB (%02Xh raw)\n", row, size, regs[drb]); + /* Write DRB register, adding the previous DRB's value. */ + if (row == 0) + regs[drb] = 0; + else if ((apollo) && (drb == apollo)) + regs[drb] = regs[drb | 0xf]; /* 5F comes before 56 */ + else + regs[drb] = regs[drb - 1]; + if (size) + regs[drb] += size / drb_unit; /* this will intentionally overflow on 440GX with 2 GB */ + spd_log("DRB[%d] = %d MB (%02Xh raw)\n", row, size, regs[drb]); } } diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index d7d9f1e90..4bca1df0a 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -32,6 +32,7 @@ #include <86box/rom.h> #include <86box/plat.h> #include <86box/video.h> +#include <86box/i2c.h> #include <86box/vid_ddc.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> @@ -251,6 +252,8 @@ typedef struct mach64_t uint32_t buf_offset[2], buf_pitch[2]; int overlay_v_acc; + + void *i2c; } mach64_t; static video_timings_t timing_mach64_isa = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; @@ -1740,7 +1743,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) mach64_t *mach64 = (mach64_t *)p; uint8_t gpio_state; - uint8_t ret; + uint8_t ret = 0xff; if (!(addr & 0x400)) { mach64_log("nmach64_ext_readb: addr=%04x\n", addr); @@ -1879,11 +1882,11 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) if ((ret & (1 << 4)) && !(ret & (1 << 1))) gpio_state &= ~(1 << 1); - if (!(ret & (1 << 4)) && !ddc_read_data()) + if (!(ret & (1 << 4)) && !i2c_gpio_get_sda(mach64->i2c)) gpio_state &= ~(1 << 1); if ((ret & (1 << 5)) && !(ret & (1 << 2))) gpio_state &= ~(1 << 2); - if (!(ret & (1 << 5)) && !ddc_read_clock()) + if (!(ret & (1 << 5)) && !i2c_gpio_get_scl(mach64->i2c)) gpio_state &= ~(1 << 2); ret = (ret & ~6) | gpio_state; @@ -2381,7 +2384,7 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) ati68860_set_ramdac_type(mach64->svga.ramdac, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); data = (val & (1 << 4)) ? ((val & (1 << 1)) ? 1 : 0) : 1; clk = (val & (1 << 5)) ? ((val & (1 << 2)) ? 1 : 0) : 1; - ddc_i2c_change(clk, data); + i2c_gpio_set(mach64->i2c, clk, data); break; case 0xd0: case 0xd1: case 0xd2: case 0xd3: @@ -3368,7 +3371,8 @@ static void *mach64_common_init(const device_t *info) mach64->fifo_not_full_event = thread_create_event(); mach64->fifo_thread = thread_create(fifo_thread, mach64); - ddc_init(); + mach64->i2c = i2c_gpio_init("ddc_ati_mach64"); + ddc_init(i2c_gpio_get_bus(mach64->i2c)); return mach64; } diff --git a/src/video/vid_ddc.c b/src/video/vid_ddc.c index 4c4aab881..7256cd970 100644 --- a/src/video/vid_ddc.c +++ b/src/video/vid_ddc.c @@ -1,6 +1,3 @@ -#include -#include -#include /* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM @@ -14,321 +11,122 @@ * * * Authors: Sarah Walker, + * RichardG, * * Copyright 2008-2020 Sarah Walker. + * Copyright 2020 RichardG. */ +#include +#include +#include #include #include #include #include #include <86box/86box.h> -#include "cpu.h" -#include <86box/vid_ddc.h> +#include <86box/i2c.h> -static uint8_t edid_data[128] = -{ - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /*Fixed header pattern*/ - 0x09, 0xf8, /*Manufacturer "BOX" - apparently unassigned by UEFI - and it has to be big endian*/ - 0x00, 0x00, /*Product code*/ - 0x12, 0x34, 0x56, 0x78, /*Serial number*/ - 0x01, 9, /*Manufacturer week and year*/ - 0x01, 0x03, /*EDID version (1.3)*/ +typedef struct { + uint8_t addr_register; +} ddc_t; - 0x08, /*Analogue input, separate sync*/ - 34, 0, /*Landscape, 4:3*/ - 0, /*Gamma*/ - 0x08, /*RGB colour*/ - 0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /*Chromaticity*/ - 0xff, 0xff, 0xff, /*Established timing bitmap*/ - 0x00, 0x00, /*Standard timing information*/ - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, +static uint8_t edid_data[128] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /* Fixed header pattern */ + 0x09, 0xf8, /* Manufacturer "BOX" - apparently unassigned by UEFI - and it has to be big endian */ + 0x00, 0x00, /* Product code */ + 0x12, 0x34, 0x56, 0x78, /* Serial number */ + 47, 30, /* Manufacturer week and year */ + 0x01, 0x03, /* EDID version (1.3) */ - /*Detailed mode descriptions*/ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, /* Analog input, separate sync */ + 34, 0, /* Landscape, 4:3 */ + 0, /* Gamma */ + 0x08, /* RGB colour */ + 0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /* Chromaticity */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, /* Established timing bitmap */ + 0x00, 0x00, /* Standard timing information */ + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Detailed mode descriptions */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, /*No extensions*/ - 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, /* No extensions */ + 0x00 }; -/*This should probably be split off into a separate I2C module*/ -enum -{ - TRANSMITTER_MONITOR = 1, - TRANSMITTER_HOST = -1 -}; -enum +uint8_t +ddc_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) { - I2C_IDLE = 0, - I2C_RECEIVE, - I2C_RECEIVE_WAIT, - I2C_TRANSMIT_START, - I2C_TRANSMIT, - I2C_ACKNOWLEDGE, - I2C_TRANSACKNOWLEDGE, - I2C_TRANSMIT_WAIT -}; - -enum -{ - PROM_IDLE = 0, - PROM_RECEIVEADDR, - PROM_RECEIVEDATA, - PROM_SENDDATA, - PROM_INVALID -}; - -static struct -{ - int clock, data; - int state; - int last_data; - int pos; - int transmit; - uint8_t byte; -} i2c; - -static struct -{ - int state; - int addr; - int rw; -} prom; - -static void prom_stop(void) -{ -// pclog("prom_stop()\n"); - prom.state = PROM_IDLE; - i2c.transmit = TRANSMITTER_HOST; + return edid_data[cmd & 0x7f]; } -static void prom_next_byte(void) + +uint8_t +ddc_read_byte(void *bus, uint8_t addr, void *priv) { -// pclog("prom_next_byte(%d)\n", prom.addr); - i2c.byte = edid_data[(prom.addr++) & 0x7F]; + ddc_t *dev = (ddc_t *) priv; + return ddc_read_byte_cmd(bus, addr, dev->addr_register++, priv); } -static void prom_write(uint8_t byte) + +uint16_t +ddc_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) { -// pclog("prom_write: byte=%02x\n", byte); - switch (prom.state) - { - case PROM_IDLE: - if ((byte & 0xfe) != 0xa0) - { -// pclog("I2C address not PROM\n"); - prom.state = PROM_INVALID; - break; - } - prom.rw = byte & 1; - if (prom.rw) - { - prom.state = PROM_SENDDATA; - i2c.transmit = TRANSMITTER_MONITOR; - i2c.byte = edid_data[(prom.addr++) & 0x7F]; -// pclog("PROM - %02X from %02X\n",i2c.byte, prom.addr-1); -// pclog("Transmitter now PROM\n"); - } - else - { - prom.state = PROM_RECEIVEADDR; - i2c.transmit = TRANSMITTER_HOST; - } -// pclog("PROM R/W=%i\n",promrw); - return; - - case PROM_RECEIVEADDR: -// pclog("PROM addr=%02X\n",byte); - prom.addr = byte; - if (prom.rw) - prom.state = PROM_SENDDATA; - else - prom.state = PROM_RECEIVEDATA; - break; - - case PROM_RECEIVEDATA: -// pclog("PROM write %02X %02X\n",promaddr,byte); - break; - - case PROM_SENDDATA: - break; - } + return (ddc_read_byte_cmd(bus, addr, cmd + 1, priv) << 8) | ddc_read_byte_cmd(bus, addr, cmd, priv); } -void ddc_i2c_change(int new_clock, int new_data) + +uint8_t +ddc_read_block_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv) { -// pclog("I2C update clock %i->%i data %i->%i state %i\n",i2c.clock,new_clock,i2c.last_data,new_data,i2c.state); - switch (i2c.state) - { - case I2C_IDLE: - if (i2c.clock && new_clock) - { - if (i2c.last_data && !new_data) /*Start bit*/ - { -// pclog("Start bit received\n"); - i2c.state = I2C_RECEIVE; - i2c.pos = 0; - } - } - break; - - case I2C_RECEIVE_WAIT: - if (!i2c.clock && new_clock) - i2c.state = I2C_RECEIVE; - case I2C_RECEIVE: - if (!i2c.clock && new_clock) - { - i2c.byte <<= 1; - if (new_data) - i2c.byte |= 1; - else - i2c.byte &= 0xFE; - i2c.pos++; - if (i2c.pos == 8) - { - prom_write(i2c.byte); - i2c.state = I2C_ACKNOWLEDGE; - } - } - else if (i2c.clock && new_clock && new_data && !i2c.last_data) /*Stop bit*/ - { -// pclog("Stop bit received\n"); - i2c.state = I2C_IDLE; - prom_stop(); - } - else if (i2c.clock && new_clock && !new_data && i2c.last_data) /*Start bit*/ - { -// pclog("Start bit received\n"); - i2c.pos = 0; - prom.state = PROM_IDLE; - } - break; - - case I2C_ACKNOWLEDGE: - if (!i2c.clock && new_clock) - { -// pclog("Acknowledging transfer\n"); - new_data = 0; - i2c.pos = 0; - if (i2c.transmit == TRANSMITTER_HOST) - i2c.state = I2C_RECEIVE_WAIT; - else - i2c.state = I2C_TRANSMIT; - } - break; - - case I2C_TRANSACKNOWLEDGE: - if (!i2c.clock && new_clock) - { - if (new_data) /*It's not acknowledged - must be end of transfer*/ - { -// pclog("End of transfer\n"); - i2c.state = I2C_IDLE; - prom_stop(); - } - else /*Next byte to transfer*/ - { - i2c.state = I2C_TRANSMIT_START; - prom_next_byte(); - i2c.pos = 0; -// pclog("Next byte - %02X\n",i2c.byte); - } - } - break; - - case I2C_TRANSMIT_WAIT: - if (i2c.clock && new_clock) - { - if (i2c.last_data && !new_data) /*Start bit*/ - { - prom_next_byte(); - i2c.pos = 0; -// pclog("Next byte - %02X\n",i2c.byte); - } - if (!i2c.last_data && new_data) /*Stop bit*/ - { -// pclog("Stop bit received\n"); - i2c.state = I2C_IDLE; - prom_stop(); - } - } - break; - - case I2C_TRANSMIT_START: - if (!i2c.clock && new_clock) - i2c.state = I2C_TRANSMIT; - if (i2c.clock && new_clock && !i2c.last_data && new_data) /*Stop bit*/ - { -// pclog("Stop bit received\n"); - i2c.state = I2C_IDLE; - prom_stop(); - } - case I2C_TRANSMIT: - if (!i2c.clock && new_clock) - { - i2c.clock = new_clock; -// if (!i2c.pos) -// pclog("Transmit byte %02x\n", i2c.byte); - i2c.data = new_data = i2c.byte & 0x80; -// pclog("Transmit bit %i %i\n", i2c.byte, i2c.pos); - i2c.byte <<= 1; - i2c.pos++; - return; - } - if (i2c.clock && !new_clock && i2c.pos == 8) - { - i2c.state = I2C_TRANSACKNOWLEDGE; -// pclog("Acknowledge mode\n"); - } - break; - - } - if (!i2c.clock && new_clock) - i2c.data = new_data; - i2c.last_data = new_data; - i2c.clock = new_clock; + uint8_t read = 0; + for (uint8_t i = cmd; (i < len) && (i < 0x80); i++) + data[read++] = ddc_read_byte_cmd(bus, addr, i, priv); + return read; } -int ddc_read_clock(void) + +void +ddc_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv) { - return i2c.clock; -} -int ddc_read_data(void) -{ - if (i2c.state == I2C_TRANSMIT || i2c.state == I2C_ACKNOWLEDGE) - return i2c.data; - if (i2c.state == I2C_RECEIVE_WAIT) - return 0; /*ACK*/ - return 1; + ddc_t *dev = (ddc_t *) priv; + dev->addr_register = val; } -void ddc_init(void) + +void +ddc_init(void *i2c) { - int c; - uint8_t checksum = 0; + ddc_t *dev = (ddc_t *) malloc(sizeof(ddc_t)); + memset(dev, 0, sizeof(ddc_t)); - for (c = 0; c < 127; c++) - checksum += edid_data[c]; - edid_data[127] = 256 - checksum; + uint8_t checksum = 0; + for (int c = 0; c < 127; c++) + checksum += edid_data[c]; + edid_data[127] = 256 - checksum; - i2c.clock = 1; - i2c.data = 1; + i2c_sethandler(i2c, 0x50, 1, + NULL, ddc_read_byte, ddc_read_byte_cmd, ddc_read_word_cmd, ddc_read_block_cmd, + NULL, ddc_write_byte, NULL, NULL, NULL, + dev); } diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 81c3b2d34..7e24e9e77 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -32,6 +32,7 @@ #include <86box/device.h> #include <86box/plat.h> #include <86box/video.h> +#include <86box/i2c.h> #include <86box/vid_ddc.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> @@ -286,6 +287,8 @@ typedef struct virge_t uint8_t subsys_stat, subsys_cntl, advfunc_cntl; uint8_t serialport; + + void *i2c; } virge_t; static video_timings_t timing_diamond_stealth3d_2000_vlb = {VIDEO_BUS, 2, 2, 3, 28, 28, 45}; @@ -894,9 +897,9 @@ s3_virge_mmio_read(uint32_t addr, void *p) case 0xff20: case 0xff21: ret = virge->serialport & ~(SERIAL_PORT_SCR | SERIAL_PORT_SDR); - if ((virge->serialport & SERIAL_PORT_SCW) && ddc_read_clock()) + if ((virge->serialport & SERIAL_PORT_SCW) && i2c_gpio_get_scl(virge->i2c)) ret |= SERIAL_PORT_SCR; - if ((virge->serialport & SERIAL_PORT_SDW) && ddc_read_data()) + if ((virge->serialport & SERIAL_PORT_SDW) && i2c_gpio_get_sda(virge->i2c)) ret |= SERIAL_PORT_SDR; return ret; } @@ -1180,7 +1183,7 @@ static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) case 0xff20: virge->serialport = val; - ddc_i2c_change((val & SERIAL_PORT_SCW) ? 1 : 0, (val & SERIAL_PORT_SDW) ? 1 : 0); + i2c_gpio_set(virge->i2c, !!(val & SERIAL_PORT_SCW), !!(val & SERIAL_PORT_SDW)); break; } } @@ -3845,7 +3848,8 @@ static void *s3_virge_init(const device_t *info) virge->fifo_not_full_event = thread_create_event(); virge->fifo_thread = thread_create(fifo_thread, virge); - ddc_init(); + virge->i2c = i2c_gpio_init("ddc_s3_virge"); + ddc_init(i2c_gpio_get_bus(virge->i2c)); return virge; } diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index bbe86cb73..dea6e2624 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -33,6 +33,7 @@ #include <86box/device.h> #include <86box/plat.h> #include <86box/video.h> +#include <86box/i2c.h> #include <86box/vid_ddc.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> @@ -116,6 +117,8 @@ typedef struct banshee_t uint32_t desktop_stride_tiled; int type; + + void *i2c; } banshee_t; enum @@ -682,7 +685,7 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) case Video_vidSerialParallelPort: banshee->vidSerialParallelPort = val; // banshee_log("vidSerialParallelPort: write %08x %08x %04x(%08x):%08x\n", val, val & (VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W), CS,cs,cpu_state.pc); - ddc_i2c_change((val & VIDSERIAL_DDC_DCK_W) ? 1 : 0, (val & VIDSERIAL_DDC_DDA_W) ? 1 : 0); + i2c_gpio_set(banshee->i2c, !!(val & VIDSERIAL_DDC_DCK_W), !!(val & VIDSERIAL_DDC_DDA_W)); break; case Video_vidScreenSize: @@ -915,9 +918,9 @@ static uint32_t banshee_ext_inl(uint16_t addr, void *p) case Video_vidSerialParallelPort: ret = banshee->vidSerialParallelPort & ~(VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R); - if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DCK_W) && ddc_read_clock()) + if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DCK_W) && i2c_gpio_get_scl(banshee->i2c)) ret |= VIDSERIAL_DDC_DCK_R; - if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DDA_W) && ddc_read_data()) + if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DDA_W) && i2c_gpio_get_sda(banshee->i2c)) ret |= VIDSERIAL_DDC_DDA_R; ret = ret & ~(VIDSERIAL_I2C_SCK_R | VIDSERIAL_I2C_SDA_R); if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SCK_W) @@ -2625,7 +2628,8 @@ static void *banshee_init_common(const device_t *info, wchar_t *fn, int has_sgra banshee->vidSerialParallelPort = VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W; - ddc_init(); + banshee->i2c = i2c_gpio_init("ddc_voodoo_banshee"); + ddc_init(i2c_gpio_get_bus(banshee->i2c)); video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_banshee); @@ -2672,6 +2676,7 @@ static void banshee_close(void *p) voodoo_card_close(banshee->voodoo); svga_close(&banshee->svga); + i2c_gpio_close(banshee->i2c); free(banshee); } diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index d8d7ba9b8..aaa2a3ad7 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -654,7 +654,7 @@ MCHOBJ := machine.o machine_table.o \ DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \ lpt.o pci_bridge.o postcard.o serial.o vpc2007.o \ - smbus.o smbus_piix4.o \ + i2c.o i2c_gpio.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o keyboard_at.o \ mouse.o \ From 739fdc46cc6c756ee841859e1cdaee35335233e6 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 20 Nov 2020 19:23:14 -0300 Subject: [PATCH 02/16] I2C overhaul part 2 --- src/acpi.c | 45 ++++- src/device/hwm_gl518sm.c | 84 ++++---- src/device/hwm_lm75.c | 116 +++++------ src/device/hwm_lm78.c | 77 +++----- src/device/i2c.c | 327 +++++++------------------------- src/device/i2c_eeprom.c | 102 ++++++++++ src/device/i2c_gpio.c | 47 +++-- src/device/smbus_piix4.c | 52 +++-- src/include/86box/acpi.h | 1 + src/include/86box/hwm.h | 2 +- src/include/86box/i2c.h | 60 ++---- src/include/86box/smbus_piix4.h | 1 + src/include/86box/spd.h | 18 +- src/include/86box/vid_ddc.h | 3 +- src/mem/spd.c | 53 +----- src/video/vid_ati_mach64.c | 7 +- src/video/vid_ddc.c | 62 +----- src/video/vid_s3_virge.c | 7 +- src/video/vid_voodoo_banshee.c | 5 +- src/win/Makefile.mingw | 2 +- 20 files changed, 430 insertions(+), 641 deletions(-) create mode 100644 src/device/i2c_eeprom.c diff --git a/src/acpi.c b/src/acpi.c index 48ff9b510..06f2d87f0 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -36,6 +36,7 @@ #include <86box/apm.h> #include <86box/acpi.h> #include <86box/machine.h> +#include <86box/i2c.h> #ifdef ENABLE_ACPI_LOG @@ -92,7 +93,7 @@ acpi_raise_smi(void *priv) if ((!dev->regs.smi_lock || !dev->regs.smi_active)) { smi_line = 1; dev->regs.smi_active = 1; - } + } } else if (dev->vendor == VEN_INTEL) { smi_line = 1; /* Clear bit 16 of GLBCTL. */ @@ -311,9 +312,18 @@ acpi_reg_read_via(int size, uint16_t addr, void *p) ret = dev->regs.gpio_val & 0xff; break; case 0x44: - /* GPIO port Output Value */ - if (size == 1) + /* GPIO port Input Value */ + if (size == 1) { ret = dev->regs.extsmi_val & 0xff; + + if (dev->i2c) { + ret &= 0xf9; + if (!(dev->regs.gpio_dir & 0x02) && i2c_gpio_get_scl(dev->i2c)) + ret |= 0x02; + if (!(dev->regs.gpio_dir & 0x04) && i2c_gpio_get_sda(dev->i2c)) + ret |= 0x04; + } + } break; case 0x46: case 0x47: /* GPO Port Output Value */ @@ -652,13 +662,25 @@ acpi_reg_write_via(int size, uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x40: /* GPIO Direction Control */ - if (size == 1) - dev->regs.gpio_dir = val & 0xff; + if (size == 1) { + dev->regs.gpio_dir = val & 0x7f; + + if (dev->i2c) { + /* Check direction as well due to pull-ups. */ + i2c_gpio_set(dev->i2c, !(dev->regs.gpio_dir & 0x02) || (dev->regs.gpio_val & 0x02), !(dev->regs.gpio_dir & 0x04) || (dev->regs.gpio_val & 0x04)); + } + } break; case 0x42: /* GPIO port Output Value */ - if (size == 1) - dev->regs.gpio_val = val & 0xff; + if (size == 1) { + dev->regs.gpio_val = val & 0x1f; + + if (dev->i2c) { + /* Check direction as well due to pull-ups. */ + i2c_gpio_set(dev->i2c, !(dev->regs.gpio_dir & 0x02) || (dev->regs.gpio_val & 0x02), !(dev->regs.gpio_dir & 0x04) || (dev->regs.gpio_val & 0x04)); + } + } break; case 0x46: case 0x47: /* GPO Port Output Value */ @@ -1184,6 +1206,12 @@ acpi_close(void *priv) { acpi_t *dev = (acpi_t *) priv; + if (dev->i2c) { + if (i2c_smbus == i2c_gpio_get_bus(dev->i2c)) + i2c_smbus = NULL; + i2c_gpio_close(dev->i2c); + } + timer_disable(&dev->timer); free(dev); @@ -1206,6 +1234,9 @@ acpi_init(const device_t *info) if (dev->vendor == VEN_INTEL) { dev->apm = device_add(&apm_pci_acpi_device); io_sethandler(0x00b2, 0x0002, acpi_apm_in, NULL, NULL, acpi_apm_out, NULL, NULL, dev); + } else if (dev->vendor == VEN_VIA) { + dev->i2c = i2c_gpio_init("smbus_vt82c586b"); + i2c_smbus = i2c_gpio_get_bus(dev->i2c); } timer_add(&dev->timer, acpi_timer_count, dev, 0); diff --git a/src/device/hwm_gl518sm.c b/src/device/hwm_gl518sm.c index 45353cd0d..7ed1b0013 100644 --- a/src/device/hwm_gl518sm.c +++ b/src/device/hwm_gl518sm.c @@ -41,17 +41,14 @@ typedef struct { uint16_t regs[32]; uint8_t addr_register; - uint8_t i2c_addr; + uint8_t i2c_addr, i2c_state; } gl518sm_t; -static uint8_t gl518sm_i2c_read_byte(void *bus, uint8_t addr, void *priv); -static uint8_t gl518sm_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv); -static uint16_t gl518sm_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv); +static void gl518sm_i2c_start(void *bus, uint8_t addr, void *priv); +static uint8_t gl518sm_i2c_read(void *bus, uint8_t addr, void *priv); static uint16_t gl518sm_read(gl518sm_t *dev, uint8_t reg); -static void gl518sm_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv); -static void gl518sm_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv); -static void gl518sm_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv); +static uint8_t gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv); static uint8_t gl518sm_write(gl518sm_t *dev, uint8_t reg, uint16_t val); static void gl518sm_reset(gl518sm_t *dev); @@ -81,41 +78,40 @@ gl518sm_remap(gl518sm_t *dev, uint8_t addr) { gl518sm_log("GL518SM: remapping to I2C %02Xh\n", addr); - i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, - NULL, gl518sm_i2c_read_byte, gl518sm_i2c_read_byte_cmd, gl518sm_i2c_read_word_cmd, NULL, - NULL, gl518sm_i2c_write_byte, gl518sm_i2c_write_byte_cmd, gl518sm_i2c_write_word_cmd, NULL, - dev); + i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, gl518sm_i2c_start, gl518sm_i2c_read, gl518sm_i2c_write, NULL, dev); - if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1, - NULL, gl518sm_i2c_read_byte, gl518sm_i2c_read_byte_cmd, gl518sm_i2c_read_word_cmd, NULL, - NULL, gl518sm_i2c_write_byte, gl518sm_i2c_write_byte_cmd, gl518sm_i2c_write_word_cmd, NULL, - dev); + if (addr < 0x80) + i2c_sethandler(i2c_smbus, addr, 1, gl518sm_i2c_start, gl518sm_i2c_read, gl518sm_i2c_write, NULL, dev); dev->i2c_addr = addr; } -static uint8_t -gl518sm_i2c_read_byte(void *bus, uint8_t addr, void *priv) +static void +gl518sm_i2c_start(void *bus, uint8_t addr, void *priv) { gl518sm_t *dev = (gl518sm_t *) priv; - return gl518sm_read(dev, dev->addr_register); + + dev->i2c_state = 0; } static uint8_t -gl518sm_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) +gl518sm_i2c_read(void *bus, uint8_t addr, void *priv) { gl518sm_t *dev = (gl518sm_t *) priv; - return gl518sm_read(dev, cmd); -} + uint16_t read = gl518sm_read(dev, dev->addr_register); + uint8_t ret = 0; + if ((dev->i2c_state == 1) && (dev->addr_register >= 0x07) && (dev->addr_register <= 0x0c)) { /* two-byte registers: read MSB first */ + dev->i2c_state = 2; + ret = read >> 8; + } else + ret = read; -static uint16_t -gl518sm_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) -{ - gl518sm_t *dev = (gl518sm_t *) priv; - return gl518sm_read(dev, cmd); + dev->addr_register++; + + return ret; } @@ -157,37 +153,35 @@ gl518sm_read(gl518sm_t *dev, uint8_t reg) break; } - /* Duplicate the low byte to the high byte on single-byte registers, although real hardware behavior is undefined. */ - if ((reg < 0x07) || (reg > 0x0c)) - ret |= ret << 8; - gl518sm_log("GL518SM: read(%02X) = %04X\n", reg, ret); return ret; } -static void -gl518sm_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv) +static uint8_t +gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) { gl518sm_t *dev = (gl518sm_t *) priv; - dev->addr_register = val; -} + switch (dev->i2c_state++) { + case 0: + dev->addr_register = data; + break; -static void -gl518sm_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv) -{ - gl518sm_t *dev = (gl518sm_t *) priv; - gl518sm_write(dev, cmd, val); -} + case 1: + gl518sm_write(dev, dev->addr_register, data); + break; + case 2: + gl518sm_write(dev, dev->addr_register, (data << 8) | gl518sm_read(dev, dev->addr_register)); + break; -static void -gl518sm_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv) -{ - gl518sm_t *dev = (gl518sm_t *) priv; - gl518sm_write(dev, cmd, val); + default: + return 0; + } + + return 1; } diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index 57a8781f9..8ee1aa06f 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -30,12 +30,9 @@ #define LM75_TEMP_TO_REG(t) ((t) << 8) -static uint8_t lm75_i2c_read_byte(void *bus, uint8_t addr, void *priv); -static uint8_t lm75_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv); -static uint16_t lm75_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv); -static void lm75_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv); -static void lm75_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv); -static void lm75_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv); +static void lm75_i2c_start(void *bus, uint8_t addr, void *priv); +static uint8_t lm75_i2c_read(void *bus, uint8_t addr, void *priv); +static uint8_t lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv); static void lm75_reset(lm75_t *dev); @@ -64,61 +61,49 @@ lm75_remap(lm75_t *dev, uint8_t addr) { lm75_log("LM75: remapping to I2C %02Xh\n", addr); - if (dev->i2c_addr < 0x80) i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, - NULL, lm75_i2c_read_byte, lm75_i2c_read_byte_cmd, lm75_i2c_read_word_cmd, NULL, - NULL, lm75_i2c_write_byte, lm75_i2c_write_byte_cmd, lm75_i2c_write_word_cmd, NULL, - dev); + if (dev->i2c_addr < 0x80) + i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, lm75_i2c_start, lm75_i2c_read, lm75_i2c_write, NULL, dev); - if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1, - NULL, lm75_i2c_read_byte, lm75_i2c_read_byte_cmd, lm75_i2c_read_word_cmd, NULL, - NULL, lm75_i2c_write_byte, lm75_i2c_write_byte_cmd, lm75_i2c_write_word_cmd, NULL, - dev); + if (addr < 0x80) + i2c_sethandler(i2c_smbus, addr, 1, lm75_i2c_start, lm75_i2c_read, lm75_i2c_write, NULL, dev); dev->i2c_addr = addr; } -static uint8_t -lm75_i2c_read_byte(void *bus, uint8_t addr, void *priv) +static void +lm75_i2c_start(void *bus, uint8_t addr, void *priv) { lm75_t *dev = (lm75_t *) priv; - return lm75_read(dev, dev->addr_register); + + dev->i2c_state = 0; } static uint8_t -lm75_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) +lm75_i2c_read(void *bus, uint8_t addr, void *priv) { lm75_t *dev = (lm75_t *) priv; - return lm75_read(dev, cmd); -} + uint8_t ret = 0; -static uint16_t -lm75_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) -{ - lm75_t *dev = (lm75_t *) priv; - uint8_t rethi = 0; - uint8_t retlo = 0; - - switch (cmd & 0x3) { + switch (dev->addr_register & 0x3) { case 0x0: /* temperature */ - rethi = lm75_read(dev, 0x0); - retlo = lm75_read(dev, 0x1); + ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x1 : 0x0); break; + case 0x1: /* configuration */ - rethi = retlo = lm75_read(dev, 0x2); + ret = lm75_read(dev, 0x2); break; + case 0x2: /* Thyst */ - rethi = lm75_read(dev, 0x3); - retlo = lm75_read(dev, 0x4); + ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x4 : 0x3); break; case 0x3: /* Tos */ - rethi = lm75_read(dev, 0x5); - retlo = lm75_read(dev, 0x6); + ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x6 : 0x5); break; } - return (retlo << 8) | rethi; /* byte-swapped for some reason */ + return ret; } @@ -130,9 +115,12 @@ lm75_read(lm75_t *dev, uint8_t reg) /* The AS99127F hardware monitor uses the addresses of its LM75 devices to access some of its proprietary registers. Pass this operation on to the main monitor address through an internal I2C call, if necessary. */ - if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) - ret = i2c_read_byte_cmd(i2c_smbus, dev->as99127f_i2c_addr, reg); - else if ((reg & 0x7) == 0x0) /* temperature high byte */ + if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) { + i2c_start(i2c_smbus, dev->as99127f_i2c_addr); + i2c_write(i2c_smbus, dev->as99127f_i2c_addr, reg); + ret = i2c_read(i2c_smbus, dev->as99127f_i2c_addr); + i2c_stop(i2c_smbus, dev->as99127f_i2c_addr); + } 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]); @@ -145,47 +133,36 @@ lm75_read(lm75_t *dev, uint8_t reg) } -static void -lm75_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv) +static uint8_t +lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) { lm75_t *dev = (lm75_t *) priv; - dev->addr_register = val; -} + if ((dev->i2c_state > 2) || ((dev->i2c_state == 2) && ((dev->addr_register & 0x3) == 0x1))) { + return 0; + } else if (dev->i2c_state == 0) { + dev->addr_register = data; + return 1; + } -static void -lm75_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv) -{ - lm75_t *dev = (lm75_t *) priv; - lm75_write(dev, cmd, val); -} - - -static void -lm75_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv) -{ - lm75_t *dev = (lm75_t *) priv; - uint8_t valhi = (val >> 8); - uint8_t vallo = (val & 0xff); - - switch (cmd & 0x3) { + switch (dev->addr_register & 0x3) { case 0x0: /* temperature */ - lm75_write(dev, 0x0, valhi); - lm75_write(dev, 0x1, vallo); + lm75_write(dev, (dev->i2c_state == 1) ? 0x1 : 0x0, data); break; + case 0x1: /* configuration */ - lm75_write(dev, 0x2, vallo); + lm75_write(dev, 0x2, data); break; + case 0x2: /* Thyst */ - lm75_write(dev, 0x3, valhi); - lm75_write(dev, 0x4, vallo); + lm75_write(dev, (dev->i2c_state == 1) ? 0x4 : 0x3, data); break; case 0x3: /* Tos */ - lm75_write(dev, 0x5, valhi); - lm75_write(dev, 0x6, vallo); + lm75_write(dev, (dev->i2c_state == 1) ? 0x6 : 0x5, data); break; - break; } + + return 1; } @@ -198,7 +175,10 @@ 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 I2C call, if necessary. */ if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) { - i2c_write_byte_cmd(i2c_smbus, dev->as99127f_i2c_addr, reg, val); + i2c_start(i2c_smbus, dev->as99127f_i2c_addr); + i2c_write(i2c_smbus, dev->as99127f_i2c_addr, reg); + i2c_write(i2c_smbus, dev->as99127f_i2c_addr, val); + i2c_stop(i2c_smbus, dev->as99127f_i2c_addr); return 1; } diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index 5817452d3..486e622c8 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -56,19 +56,16 @@ typedef struct { uint8_t addr_register; uint8_t data_register; - uint8_t i2c_addr; + uint8_t i2c_addr, i2c_state; } lm78_t; +static void lm78_i2c_start(void *bus, uint8_t addr, void *priv); static uint8_t lm78_isa_read(uint16_t port, void *priv); -static uint8_t lm78_i2c_read_byte(void *bus, uint8_t addr, void *priv); -static uint8_t lm78_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv); -static uint16_t lm78_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv); +static uint8_t lm78_i2c_read(void *bus, uint8_t addr, void *priv); static uint8_t lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank); static void lm78_isa_write(uint16_t port, uint8_t val, void *priv); -static void lm78_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv); -static void lm78_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv); -static void lm78_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv); +static uint8_t lm78_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv); static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank); static void lm78_reset(lm78_t *dev, uint8_t initialization); @@ -100,17 +97,12 @@ lm78_remap(lm78_t *dev, uint8_t addr) if (!(dev->local & LM78_I2C)) return; - lm78_log("LM78: remapping to I2C %02Xh\n", addr); + lm78_log("LM78: remapping to SMBus %02Xh\n", addr); - i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, - NULL, lm78_i2c_read_byte, lm78_i2c_read_byte_cmd, lm78_i2c_read_word_cmd, NULL, - NULL, lm78_i2c_write_byte, lm78_i2c_write_byte_cmd, lm78_i2c_write_word_cmd, NULL, - dev); + i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, lm78_i2c_start, lm78_i2c_read, lm78_i2c_write, NULL, dev); - if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1, - NULL, lm78_i2c_read_byte, lm78_i2c_read_byte_cmd, lm78_i2c_read_word_cmd, NULL, - NULL, lm78_i2c_write_byte, lm78_i2c_write_byte_cmd, lm78_i2c_write_word_cmd, NULL, - dev); + if (addr < 0x80) + i2c_sethandler(i2c_smbus, addr, 1, lm78_i2c_start, lm78_i2c_read, lm78_i2c_write, NULL, dev); dev->i2c_addr = addr; @@ -126,6 +118,15 @@ lm78_remap(lm78_t *dev, uint8_t addr) } +static void +lm78_i2c_start(void *bus, uint8_t addr, void *priv) +{ + lm78_t *dev = (lm78_t *) priv; + + dev->i2c_state = 0; +} + + static uint8_t lm78_isa_read(uint16_t port, void *priv) { @@ -159,26 +160,11 @@ lm78_isa_read(uint16_t port, void *priv) static uint8_t -lm78_i2c_read_byte(void *bus, uint8_t addr, void *priv) +lm78_i2c_read(void *bus, uint8_t addr, void *priv) { lm78_t *dev = (lm78_t *) priv; - return lm78_read(dev, dev->addr_register, LM78_WINBOND_BANK); -} - -static uint8_t -lm78_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) -{ - lm78_t *dev = (lm78_t *) priv; - return lm78_read(dev, cmd, LM78_WINBOND_BANK); -} - - -static uint16_t -lm78_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) -{ - lm78_t *dev = (lm78_t *) priv; - return (lm78_read(dev, cmd, LM78_WINBOND_BANK) << 8) | lm78_read(dev, cmd, LM78_WINBOND_BANK); + return lm78_read(dev, dev->addr_register++, LM78_WINBOND_BANK); } @@ -264,27 +250,18 @@ lm78_isa_write(uint16_t port, uint8_t val, void *priv) } -static void -lm78_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv) +static uint8_t +lm78_i2c_write(void *bus, uint8_t addr, uint8_t val, void *priv) { lm78_t *dev = (lm78_t *) priv; - dev->addr_register = val; -} + if (dev->i2c_state == 0) { + dev->i2c_state = 1; + dev->addr_register = val; + } else + lm78_write(dev, dev->addr_register++, val, LM78_WINBOND_BANK); -static void -lm78_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv) -{ - lm78_t *dev = (lm78_t *) priv; - lm78_write(dev, cmd, val, LM78_WINBOND_BANK); -} - - -static void -lm78_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv) -{ - lm78_t *dev = (lm78_t *) priv; - lm78_write(dev, cmd, val, LM78_WINBOND_BANK); + return 1; } diff --git a/src/device/i2c.c b/src/device/i2c.c index 20201c990..7dabc9908 100644 --- a/src/device/i2c.c +++ b/src/device/i2c.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * Implement the I2C bus and its operations. + * Implementation of the I2C bus and its operations. * * * @@ -30,17 +30,10 @@ typedef struct _i2c_ { - void (*read_quick)(void *bus, uint8_t addr, void *priv); - uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv); - uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv); - uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv); - uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv); - - void (*write_quick)(void *bus, uint8_t addr, void *priv); - void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv); - void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv); - void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv); - void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv); + void (*start)(void *bus, uint8_t addr, void *priv); + uint8_t (*read)(void *bus, uint8_t addr, void *priv); + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv); + void (*stop)(void *bus, uint8_t addr, void *priv); void *priv; @@ -55,7 +48,7 @@ typedef struct { void *i2c_smbus; -#define ENABLE_I2C_LOG 1 + #ifdef ENABLE_I2C_LOG int i2c_do_log = ENABLE_I2C_LOG; @@ -100,16 +93,10 @@ i2c_removebus(void *bus_handle) void i2c_sethandler(void *bus_handle, uint8_t base, int size, - void (*read_quick)(void *bus, uint8_t addr, void *priv), - uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_quick)(void *bus, uint8_t addr, void *priv), - void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void (*start)(void *bus, uint8_t addr, void *priv), + uint8_t (*read)(void *bus, uint8_t addr, void *priv), + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), + void (*stop)(void *bus, uint8_t addr, void *priv), void *priv) { int c; @@ -131,15 +118,10 @@ i2c_sethandler(void *bus_handle, uint8_t base, int size, q->prev = NULL; } - q->read_byte = read_byte; - q->read_byte_cmd = read_byte_cmd; - q->read_word_cmd = read_word_cmd; - q->read_block_cmd = read_block_cmd; - - q->write_byte = write_byte; - q->write_byte_cmd = write_byte_cmd; - q->write_word_cmd = write_word_cmd; - q->write_block_cmd = write_block_cmd; + q->start = start; + q->read = read; + q->write = write; + q->stop = stop; q->priv = priv; q->next = NULL; @@ -151,16 +133,10 @@ i2c_sethandler(void *bus_handle, uint8_t base, int size, void i2c_removehandler(void *bus_handle, uint8_t base, int size, - void (*read_quick)(void *bus, uint8_t addr, void *priv), - uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_quick)(void *bus, uint8_t addr, void *priv), - void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void (*start)(void *bus, uint8_t addr, void *priv), + uint8_t (*read)(void *bus, uint8_t addr, void *priv), + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), + void (*stop)(void *bus, uint8_t addr, void *priv), void *priv) { int c; @@ -176,11 +152,7 @@ i2c_removehandler(void *bus_handle, uint8_t base, int size, continue; while(p) { q = p->next; - if ((p->read_byte == read_byte) && (p->read_byte_cmd == read_byte_cmd) && - (p->read_word_cmd == read_word_cmd) && (p->read_block_cmd == read_block_cmd) && - (p->write_byte == write_byte) && (p->write_byte_cmd == write_byte_cmd) && - (p->write_word_cmd == write_word_cmd) && (p->write_block_cmd == write_block_cmd) && - (p->priv == priv)) { + if ((p->read == read) && (p->write == write) && (p->priv == priv)) { if (p->prev) p->prev->next = p->next; else @@ -201,22 +173,16 @@ i2c_removehandler(void *bus_handle, uint8_t base, int size, void i2c_handler(int set, void *bus_handle, uint8_t base, int size, - void (*read_quick)(void *bus, uint8_t addr, void *priv), - uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_quick)(void *bus, uint8_t addr, void *priv), - void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void (*start)(void *bus, uint8_t addr, void *priv), + uint8_t (*read)(void *bus, uint8_t addr, void *priv), + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), + void (*stop)(void *bus, uint8_t addr, void *priv), void *priv) { if (set) - i2c_sethandler(bus_handle, base, size, read_quick, read_byte, read_byte_cmd, read_word_cmd, read_block_cmd, write_quick, write_byte, write_byte_cmd, write_word_cmd, write_block_cmd, priv); + i2c_sethandler(bus_handle, base, size, start, read, write, stop, priv); else - i2c_removehandler(bus_handle, base, size, read_quick, read_byte, read_byte_cmd, read_word_cmd, read_block_cmd, write_quick, write_byte, write_byte_cmd, write_word_cmd, write_block_cmd, priv); + i2c_removehandler(bus_handle, base, size, start, read, write, stop, priv); } @@ -233,11 +199,10 @@ i2c_has_device(void *bus_handle, uint8_t addr) void -i2c_read_quick(void *bus_handle, uint8_t addr) +i2c_start(void *bus_handle, uint8_t addr) { i2c_bus_t *bus = (i2c_bus_t *) bus_handle; i2c_t *p; - int found = 0; if (!bus) return; @@ -245,106 +210,23 @@ i2c_read_quick(void *bus_handle, uint8_t addr) p = bus->devices[addr]; if (p) { while(p) { - if (p->read_byte) { - p->read_quick(bus_handle, addr, p->priv); - found++; + if (p->start) { + p->start(bus_handle, addr, p->priv); } p = p->next; } } - i2c_log("I2C: read_quick(%s, %02X)\n", bus->name, addr); + i2c_log("I2C: start(%s, %02X)\n", bus->name, addr); } uint8_t -i2c_read_byte(void *bus_handle, uint8_t addr) -{ - uint8_t ret = 0xff; - i2c_bus_t *bus = (i2c_bus_t *) bus_handle; - i2c_t *p; - int found = 0; - - if (!bus) - return(ret); - - p = bus->devices[addr]; - if (p) { - while(p) { - if (p->read_byte) { - ret &= p->read_byte(bus_handle, addr, p->priv); - found++; - } - p = p->next; - } - } - - i2c_log("I2C: read_byte(%s, %02X) = %02X\n", bus->name, addr, ret); - - return(ret); -} - -uint8_t -i2c_read_byte_cmd(void *bus_handle, uint8_t addr, uint8_t cmd) -{ - uint8_t ret = 0xff; - i2c_bus_t *bus = (i2c_bus_t *) bus_handle; - i2c_t *p; - int found = 0; - - if (!bus) - return(ret); - - p = bus->devices[addr]; - if (p) { - while(p) { - if (p->read_byte_cmd) { - ret &= p->read_byte_cmd(bus_handle, addr, cmd, p->priv); - found++; - } - p = p->next; - } - } - - i2c_log("I2C: read_byte_cmd(%s, %02X, %02X) = %02X\n", bus->name, addr, cmd, ret); - - return(ret); -} - -uint16_t -i2c_read_word_cmd(void *bus_handle, uint8_t addr, uint8_t cmd) -{ - uint16_t ret = 0xffff; - i2c_bus_t *bus = (i2c_bus_t *) bus_handle; - i2c_t *p; - int found = 0; - - if (!bus) - return(ret); - - p = bus->devices[addr]; - if (p) { - while(p) { - if (p->read_word_cmd) { - ret &= p->read_word_cmd(bus_handle, addr, cmd, p->priv); - found++; - } - p = p->next; - } - } - - i2c_log("I2C: read_word_cmd(%s, %02X, %02X) = %04X\n", bus->name, addr, cmd, ret); - - return(ret); -} - -uint8_t -i2c_read_block_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len) +i2c_read(void *bus_handle, uint8_t addr) { uint8_t ret = 0; i2c_bus_t *bus = (i2c_bus_t *) bus_handle; i2c_t *p; - int found = 0; if (!bus) return(ret); @@ -352,26 +234,51 @@ i2c_read_block_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t *data, u p = bus->devices[addr]; if (p) { while(p) { - if (p->read_block_cmd) { - ret = MAX(ret, p->read_block_cmd(bus_handle, addr, cmd, data, len, p->priv)); - found++; + if (p->read) { + ret = p->read(bus_handle, addr, p->priv); + break; } p = p->next; } } - i2c_log("I2C: read_block_cmd(%s, %02X, %02X) = %02X\n", bus->name, addr, cmd, len); + i2c_log("I2C: read(%s, %02X) = %02X\n", bus->name, addr, ret); + + return(ret); +} + + +uint8_t +i2c_write(void *bus_handle, uint8_t addr, uint8_t data) +{ + uint8_t ret = 0; + i2c_t *p; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + + if (!bus) + return(ret); + + p = bus->devices[addr]; + if (p) { + while(p) { + if (p->write) { + ret = p->write(bus_handle, addr, data, p->priv); + } + p = p->next; + } + } + + i2c_log("I2C: write(%s, %02X, %02X) = %d\n", bus->name, addr, data, ret); return(ret); } void -i2c_write_quick(void *bus_handle, uint8_t addr) +i2c_stop(void *bus_handle, uint8_t addr) { i2c_bus_t *bus = (i2c_bus_t *) bus_handle; i2c_t *p; - int found = 0; if (!bus) return; @@ -379,118 +286,12 @@ i2c_write_quick(void *bus_handle, uint8_t addr) p = bus->devices[addr]; if (p) { while(p) { - if (p->read_byte) { - p->write_quick(bus_handle, addr, p->priv); - found++; + if (p->stop) { + p->stop(bus_handle, addr, p->priv); } p = p->next; } } - i2c_log("I2C: write_quick(%s, %02X)\n", bus->name, addr); -} - - -void -i2c_write_byte(void *bus_handle, uint8_t addr, uint8_t val) -{ - i2c_t *p; - i2c_bus_t *bus = (i2c_bus_t *) bus_handle; - int found = 0; - - if (!bus) - return; - - if (bus->devices[addr]) { - p = bus->devices[addr]; - while(p) { - if (p->write_byte) { - p->write_byte(bus_handle, addr, val, p->priv); - found++; - } - p = p->next; - } - } - - i2c_log("I2C: write_byte(%s, %02X, %02X)\n", bus->name, addr, val); - - return; -} - -void -i2c_write_byte_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t val) -{ - i2c_t *p; - i2c_bus_t *bus = (i2c_bus_t *) bus_handle; - int found = 0; - - if (!bus) - return; - - if (bus->devices[addr]) { - p = bus->devices[addr]; - while(p) { - if (p->write_byte_cmd) { - p->write_byte_cmd(bus_handle, addr, cmd, val, p->priv); - found++; - } - p = p->next; - } - } - - i2c_log("I2C: write_byte_cmd(%s, %02X, %02X, %02X)\n", bus->name, addr, cmd, val); - - return; -} - -void -i2c_write_word_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint16_t val) -{ - i2c_t *p; - i2c_bus_t *bus = (i2c_bus_t *) bus_handle; - int found = 0; - - if (!bus) - return; - - if (bus->devices[addr]) { - p = bus->devices[addr]; - while(p) { - if (p->write_word_cmd) { - p->write_word_cmd(bus_handle, addr, cmd, val, p->priv); - found++; - } - p = p->next; - } - } - - i2c_log("I2C: write_word_cmd(%s, %02X, %02X, %04X)\n", bus->name, addr, cmd, val); - - return; -} - -void -i2c_write_block_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len) -{ - i2c_t *p; - i2c_bus_t *bus = (i2c_bus_t *) bus_handle; - int found = 0; - - if (!bus) - return; - - p = bus->devices[addr]; - if (p) { - while(p) { - if (p->write_block_cmd) { - p->write_block_cmd(bus_handle, addr, cmd, data, len, p->priv); - found++; - } - p = p->next; - } - } - - i2c_log("I2C: write_block_cmd(%s, %02X, %02X, %02X)\n", bus->name, addr, cmd, len); - - return; + i2c_log("I2C: stop(%s, %02X)\n", bus->name, addr); } diff --git a/src/device/i2c_eeprom.c b/src/device/i2c_eeprom.c new file mode 100644 index 000000000..7696955e8 --- /dev/null +++ b/src/device/i2c_eeprom.c @@ -0,0 +1,102 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the AT24Cxx series of I2C EEPROMs. + * + * + * + * Authors: RichardG, + * + * Copyright 2020 RichardG. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include <86box/86box.h> +#include <86box/i2c.h> + + +typedef struct { + void *i2c; + uint8_t addr; + uint8_t *data; + uint8_t writable; + + uint16_t addr_mask; + uint8_t addr_register; + uint8_t i2c_state; +} i2c_eeprom_t; + + +void +i2c_eeprom_start(void *bus, uint8_t addr, void *priv) +{ + i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; + + dev->i2c_state = 0; +} + + +uint8_t +i2c_eeprom_read(void *bus, uint8_t addr, void *priv) +{ + i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; + + return dev->data[((addr << 8) | dev->addr_register++) & dev->addr_mask]; +} + + +uint8_t +i2c_eeprom_write(void *bus, uint8_t addr, uint8_t data, void *priv) +{ + i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; + + if (dev->i2c_state == 0) { + dev->i2c_state = 1; + dev->addr_register = data; + } else if (dev->writable) + dev->data[((addr << 8) | dev->addr_register++) & dev->addr_mask] = data; + else + return 0; + + return 1; +} + + +void * +i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint16_t size, uint8_t writable) +{ + i2c_eeprom_t *dev = (i2c_eeprom_t *) malloc(sizeof(i2c_eeprom_t)); + memset(dev, 0, sizeof(i2c_eeprom_t)); + + dev->i2c = i2c; + dev->addr = addr; + dev->data = data; + dev->writable = writable; + + dev->addr_mask = size - 1; + + i2c_sethandler(i2c, dev->addr & ~(dev->addr_mask >> 8), (dev->addr_mask >> 8) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev); + + return dev; +} + + +void +i2c_eeprom_close(void *dev_handle) +{ + i2c_eeprom_t *dev = (i2c_eeprom_t *) dev_handle; + + i2c_removehandler(dev->i2c, dev->addr & ~(dev->addr_mask >> 8), (dev->addr_mask >> 8) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev); + + free(dev); +} diff --git a/src/device/i2c_gpio.c b/src/device/i2c_gpio.c index decf52117..e2b844200 100644 --- a/src/device/i2c_gpio.c +++ b/src/device/i2c_gpio.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * Implementation of a GPIO-based I2C device. + * Emulation of a GPIO-based I2C device. * * * @@ -16,13 +16,13 @@ * Copyright 2008-2020 Sarah Walker. * Copyright 2020 RichardG. */ +#include #include #include -#include #include -#include +#include +#define HAVE_STDARG_H #include -#include #include <86box/86box.h> #include <86box/i2c.h> @@ -53,8 +53,8 @@ enum { typedef struct { void *i2c; - uint8_t scl, sda, state, slave_state, slave_addr, slave_reg, - slave_writing, slave_rw, last_sda, pos, transmit, byte; + uint8_t scl, sda, state, slave_state, slave_addr, + slave_rw, last_sda, pos, transmit, byte; } i2c_gpio_t; @@ -66,6 +66,7 @@ i2c_gpio_init(char *bus_name) dev->i2c = i2c_addbus(bus_name); dev->scl = dev->sda = 1; + dev->slave_addr = 0xff; return dev; } @@ -85,49 +86,46 @@ i2c_gpio_close(void *dev_handle) void i2c_gpio_next_byte(i2c_gpio_t *dev) { - dev->byte = i2c_read_byte(dev->i2c, dev->slave_addr); + dev->byte = i2c_read(dev->i2c, dev->slave_addr); } void i2c_gpio_write(i2c_gpio_t *dev) { + uint8_t i; + switch (dev->slave_state) { case SLAVE_IDLE: + i = dev->slave_addr; dev->slave_addr = dev->byte >> 1; + dev->slave_rw = dev->byte & 1; + if (!i2c_has_device(dev->i2c, dev->slave_addr)) { dev->slave_state = SLAVE_INVALID; break; } - dev->slave_rw = dev->byte & 1; - dev->slave_writing = 0; + + if (i == 0xff) + i2c_start(dev->i2c, dev->slave_addr); + if (dev->slave_rw) { dev->slave_state = SLAVE_SENDDATA; dev->transmit = TRANSMITTER_SLAVE; - dev->byte = i2c_read_byte(dev->i2c, dev->slave_addr); + dev->byte = i2c_read(dev->i2c, dev->slave_addr); } else { dev->slave_state = SLAVE_RECEIVEADDR; dev->transmit = TRANSMITTER_MASTER; } - pclog("slave_idle %02X %d\n", dev->slave_addr, dev->slave_rw); break; case SLAVE_RECEIVEADDR: - pclog("slave_receiveaddr %02X %d\n", dev->slave_addr, dev->slave_rw); - i2c_write_byte(dev->i2c, dev->slave_addr, dev->byte); - dev->slave_writing = 1; - dev->slave_reg = dev->byte; + i2c_write(dev->i2c, dev->slave_addr, dev->byte); dev->slave_state = dev->slave_rw ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA; break; case SLAVE_RECEIVEDATA: - pclog("slave_receivedata %02X %d = %02X\n", dev->slave_addr, dev->slave_rw, dev->byte); - dev->slave_writing = 0; - i2c_write_byte_cmd(dev->i2c, dev->slave_addr, dev->slave_reg, dev->byte); - break; - - case SLAVE_SENDDATA: - pclog("slave_senddata %02X %d = %02X\n", dev->slave_addr, dev->slave_rw, dev->byte); + i2c_write(dev->i2c, dev->slave_addr, dev->byte); break; } } @@ -136,10 +134,9 @@ i2c_gpio_write(i2c_gpio_t *dev) void i2c_gpio_stop(i2c_gpio_t *dev) { - pclog("stopping... state = %d\n", dev->slave_state); - if (dev->slave_writing) - i2c_write_byte(dev->i2c, dev->slave_addr, dev->slave_reg); + i2c_stop(dev->i2c, dev->slave_addr); + dev->slave_addr = 0xff; dev->slave_state = SLAVE_IDLE; dev->transmit = TRANSMITTER_MASTER; } diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index e8cd32eb2..100a31ab8 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -99,7 +99,6 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) { smbus_piix4_t *dev = (smbus_piix4_t *) priv; uint8_t smbus_addr, smbus_read, prev_stat; - uint16_t temp; smbus_piix4_log("SMBus PIIX4: write(%02X, %02X)\n", addr, val); @@ -132,46 +131,53 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) } smbus_read = dev->addr & 0x01; + /* start transaction */ + i2c_start(i2c_smbus, smbus_addr); + /* decode the 3-bit command protocol */ dev->next_stat = 0x2; /* raise INTER (command completed) by default */ switch ((val >> 2) & 0x7) { case 0x0: /* quick R/W */ - if (smbus_read) - i2c_read_quick(i2c_smbus, smbus_addr); - else - i2c_write_quick(i2c_smbus, smbus_addr); break; case 0x1: /* byte R/W */ if (smbus_read) - dev->data0 = i2c_read_byte(i2c_smbus, smbus_addr); + dev->data0 = i2c_read(i2c_smbus, smbus_addr); else - i2c_write_byte(i2c_smbus, smbus_addr, dev->data0); + i2c_write(i2c_smbus, smbus_addr, dev->data0); break; case 0x2: /* byte data R/W */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); if (smbus_read) - dev->data0 = i2c_read_byte_cmd(i2c_smbus, smbus_addr, dev->cmd); + dev->data0 = i2c_read(i2c_smbus, smbus_addr); else - i2c_write_byte_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data0); + i2c_write(i2c_smbus, smbus_addr, dev->data0); break; case 0x3: /* word data R/W */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); if (smbus_read) { - temp = i2c_read_word_cmd(i2c_smbus, smbus_addr, dev->cmd); - dev->data0 = temp; - dev->data1 = temp >> 8; + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + dev->data1 = i2c_read(i2c_smbus, smbus_addr); } else { - temp = (dev->data1 << 8) | dev->data0; - i2c_write_word_cmd(i2c_smbus, smbus_addr, dev->cmd, temp); + i2c_write(i2c_smbus, smbus_addr, dev->data0); + i2c_write(i2c_smbus, smbus_addr, dev->data1); } break; case 0x5: /* block R/W */ - if (smbus_read) - dev->data0 = i2c_read_block_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data, SMBUS_PIIX4_BLOCK_DATA_SIZE); - else - i2c_write_block_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data, dev->data0); + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + /* SMBus block data is preceded by a length */ + if (smbus_read) { + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + for (smbus_read = 0; smbus_read < MIN(SMBUS_PIIX4_BLOCK_DATA_SIZE, dev->data0); smbus_read++) + dev->data[smbus_read] = i2c_read(i2c_smbus, smbus_addr); + } else { + i2c_write(i2c_smbus, smbus_addr, dev->data0); + for (smbus_read = 0; smbus_read < MIN(SMBUS_PIIX4_BLOCK_DATA_SIZE, dev->data0); smbus_read++) + i2c_write(i2c_smbus, smbus_addr, dev->data[smbus_read]); + } break; default: @@ -179,6 +185,9 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) dev->next_stat = 0x4; break; } + + /* stop transaction */ + i2c_stop(i2c_smbus, smbus_addr); } break; @@ -244,7 +253,7 @@ smbus_piix4_init(const device_t *info) smbus_piix4_t *dev = (smbus_piix4_t *) malloc(sizeof(smbus_piix4_t)); memset(dev, 0, sizeof(smbus_piix4_t)); - i2c_smbus = i2c_addbus("smbus_piix4"); + i2c_smbus = dev->i2c = i2c_addbus("smbus_piix4"); timer_add(&dev->response_timer, smbus_piix4_response, dev, 0); @@ -257,8 +266,9 @@ smbus_piix4_close(void *priv) { smbus_piix4_t *dev = (smbus_piix4_t *) priv; - i2c_removebus(i2c_smbus); - i2c_smbus = NULL; + if (i2c_smbus == dev->i2c) + i2c_smbus = NULL; + i2c_removebus(dev->i2c); free(dev); } diff --git a/src/include/86box/acpi.h b/src/include/86box/acpi.h index ab5c1e9f2..0e5e688ef 100644 --- a/src/include/86box/acpi.h +++ b/src/include/86box/acpi.h @@ -84,6 +84,7 @@ typedef struct pc_timer_t timer; nvr_t *nvr; apm_t *apm; + void *i2c; } acpi_t; diff --git a/src/include/86box/hwm.h b/src/include/86box/hwm.h index d77437bde..95d14cf6a 100644 --- a/src/include/86box/hwm.h +++ b/src/include/86box/hwm.h @@ -35,7 +35,7 @@ typedef struct { uint8_t regs[8]; uint8_t addr_register; uint8_t temp_idx; - uint8_t i2c_addr; + uint8_t i2c_addr, i2c_state; uint8_t as99127f_i2c_addr; } lm75_t; diff --git a/src/include/86box/i2c.h b/src/include/86box/i2c.h index 5c94f766e..8db7efb7d 100644 --- a/src/include/86box/i2c.h +++ b/src/include/86box/i2c.h @@ -27,55 +27,35 @@ extern void *i2c_addbus(char *name); extern void i2c_removebus(void *bus_handle); extern void i2c_sethandler(void *bus_handle, uint8_t base, int size, - void (*read_quick)(void *bus, uint8_t addr, void *priv), - uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_quick)(void *bus, uint8_t addr, void *priv), - void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void (*start)(void *bus, uint8_t addr, void *priv), + uint8_t (*read)(void *bus, uint8_t addr, void *priv), + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), + void (*stop)(void *bus, uint8_t addr, void *priv), void *priv); extern void i2c_removehandler(void *bus_handle, uint8_t base, int size, - void (*read_quick)(void *bus, uint8_t addr, void *priv), - uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_quick)(void *bus, uint8_t addr, void *priv), - void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void (*start)(void *bus, uint8_t addr, void *priv), + uint8_t (*read)(void *bus, uint8_t addr, void *priv), + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), + void (*stop)(void *bus, uint8_t addr, void *priv), void *priv); extern void i2c_handler(int set, void *bus_handle, uint8_t base, int size, - void (*read_quick)(void *bus, uint8_t addr, void *priv), - uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv), - uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), - uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv), - uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), - void (*write_quick)(void *bus, uint8_t addr, void *priv), - void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv), - void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv), - void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv), - void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv), + void (*start)(void *bus, uint8_t addr, void *priv), + uint8_t (*read)(void *bus, uint8_t addr, void *priv), + uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), + void (*stop)(void *bus, uint8_t addr, void *priv), void *priv); extern uint8_t i2c_has_device(void *bus_handle, uint8_t addr); -extern void i2c_read_quick(void *bus_handle, uint8_t addr); -extern uint8_t i2c_read_byte(void *bus_handle, uint8_t addr); -extern uint8_t i2c_read_byte_cmd(void *bus_handle, uint8_t addr, uint8_t cmd); -extern uint16_t i2c_read_word_cmd(void *bus_handle, uint8_t addr, uint8_t cmd); -extern uint8_t i2c_read_block_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len); -extern void i2c_write_quick(void *bus_handle, uint8_t addr); -extern void i2c_write_byte(void *bus_handle, uint8_t addr, uint8_t val); -extern void i2c_write_byte_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t val); -extern void i2c_write_word_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint16_t val); -extern void i2c_write_block_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len); +extern void i2c_start(void *bus_handle, uint8_t addr); +extern uint8_t i2c_read(void *bus_handle, uint8_t addr); +extern uint8_t i2c_write(void *bus_handle, uint8_t addr, uint8_t data); +extern void i2c_stop(void *bus_handle, uint8_t addr); + +/* i2c_eeprom.c */ +extern void *i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint16_t size, uint8_t writable); +extern void i2c_eeprom_close(void *dev_handle); /* i2c_gpio.c */ extern void *i2c_gpio_init(char *bus_name); diff --git a/src/include/86box/smbus_piix4.h b/src/include/86box/smbus_piix4.h index b9f776a5a..aa7188393 100644 --- a/src/include/86box/smbus_piix4.h +++ b/src/include/86box/smbus_piix4.h @@ -29,6 +29,7 @@ typedef struct index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE]; pc_timer_t response_timer; + void *i2c; } smbus_piix4_t; diff --git a/src/include/86box/spd.h b/src/include/86box/spd.h index 4acce679d..848210922 100644 --- a/src/include/86box/spd.h +++ b/src/include/86box/spd.h @@ -47,17 +47,17 @@ #define SPD_SDR_ATTR_VCC_HI_5 0x20 -typedef struct _spd_ { - const device_t *info; - uint8_t slot; - uint16_t size; - uint16_t row1; - uint16_t row2; +typedef struct { + const device_t *info; + uint8_t slot; + uint16_t size; + uint16_t row1; + uint16_t row2; - uint8_t addr_register; + void *eeprom; } spd_t; -typedef struct _spd_edo_ { +typedef struct { uint8_t bytes_used, spd_size, mem_type, row_bits, col_bits, banks, data_width_lsb, data_width_msb, @@ -75,7 +75,7 @@ typedef struct _spd_edo_ { checksum2; } spd_edo_t; -typedef struct _spd_sdram_ { +typedef struct { uint8_t bytes_used, spd_size, mem_type, row_bits, col_bits, rows, data_width_lsb, data_width_msb, diff --git a/src/include/86box/vid_ddc.h b/src/include/86box/vid_ddc.h index b2f3e50e9..aa5ee86ba 100644 --- a/src/include/86box/vid_ddc.h +++ b/src/include/86box/vid_ddc.h @@ -19,6 +19,7 @@ #ifndef EMU_VID_DDC_H # define EMU_VID_DDC_H -extern void ddc_init(void *i2c); +extern void *ddc_init(void *i2c); +extern void ddc_close(void *dev_handle); #endif /*EMU_VID_DDC_H*/ diff --git a/src/mem/spd.c b/src/mem/spd.c index 9f1285754..6ace702c1 100644 --- a/src/mem/spd.c +++ b/src/mem/spd.c @@ -57,49 +57,6 @@ spd_log(const char *fmt, ...) #endif -uint8_t -spd_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) -{ - spd_t *dev = (spd_t *) priv; - uint8_t ret = *(spd_data[dev->slot] + cmd); - spd_log("SPD: read(%02X, %02X) = %02X\n", addr, cmd, ret); - return ret; -} - - -uint8_t -spd_read_byte(void *bus, uint8_t addr, void *priv) -{ - spd_t *dev = (spd_t *) priv; - return spd_read_byte_cmd(bus, addr, dev->addr_register, priv); -} - - -uint16_t -spd_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) -{ - return (spd_read_byte_cmd(bus, addr, cmd + 1, priv) << 8) | spd_read_byte_cmd(bus, addr, cmd, priv); -} - - -uint8_t -spd_read_block_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv) -{ - uint8_t read = 0; - for (uint8_t i = cmd; (i < len) && (i < SPD_DATA_SIZE); i++) - data[read++] = spd_read_byte_cmd(bus, addr, i, priv); - return read; -} - - -void -spd_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv) -{ - spd_t *dev = (spd_t *) priv; - dev->addr_register = val; -} - - static void spd_close(void *priv) { @@ -107,10 +64,7 @@ spd_close(void *priv) spd_log("SPD: closing slot %d (SMBus %02X)\n", dev->slot, SPD_BASE_ADDR + dev->slot); - i2c_removehandler(i2c_smbus, SPD_BASE_ADDR + dev->slot, 1, - NULL, spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd, - NULL, spd_write_byte, NULL, NULL, NULL, - dev); + i2c_eeprom_close(dev->eeprom); spd_present = 0; @@ -125,10 +79,7 @@ spd_init(const device_t *info) spd_log("SPD: initializing slot %d (SMBus %02X)\n", dev->slot, SPD_BASE_ADDR + dev->slot); - i2c_sethandler(i2c_smbus, SPD_BASE_ADDR + dev->slot, 1, - NULL, spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd, - NULL, spd_write_byte, NULL, NULL, NULL, - dev); + dev->eeprom = i2c_eeprom_init(i2c_smbus, SPD_BASE_ADDR + dev->slot, spd_data[info->local], SPD_DATA_SIZE, 0); spd_present = 1; diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 4bca1df0a..a353fd6e6 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -253,7 +253,7 @@ typedef struct mach64_t int overlay_v_acc; - void *i2c; + void *i2c, *ddc; } mach64_t; static video_timings_t timing_mach64_isa = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; @@ -3372,7 +3372,7 @@ static void *mach64_common_init(const device_t *info) mach64->fifo_thread = thread_create(fifo_thread, mach64); mach64->i2c = i2c_gpio_init("ddc_ati_mach64"); - ddc_init(i2c_gpio_get_bus(mach64->i2c)); + mach64->ddc = ddc_init(i2c_gpio_get_bus(mach64->i2c)); return mach64; } @@ -3464,6 +3464,9 @@ void mach64_close(void *p) thread_destroy_event(mach64->wake_fifo_thread); thread_destroy_event(mach64->fifo_not_full_event); + ddc_close(mach64->ddc); + i2c_gpio_close(mach64->i2c); + free(mach64); } diff --git a/src/video/vid_ddc.c b/src/video/vid_ddc.c index 7256cd970..45788842e 100644 --- a/src/video/vid_ddc.c +++ b/src/video/vid_ddc.c @@ -27,11 +27,6 @@ #include <86box/i2c.h> -typedef struct { - uint8_t addr_register; -} ddc_t; - - static uint8_t edid_data[128] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /* Fixed header pattern */ 0x09, 0xf8, /* Manufacturer "BOX" - apparently unassigned by UEFI - and it has to be big endian */ @@ -74,59 +69,20 @@ static uint8_t edid_data[128] = { }; -uint8_t -ddc_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) -{ - return edid_data[cmd & 0x7f]; -} - - -uint8_t -ddc_read_byte(void *bus, uint8_t addr, void *priv) -{ - ddc_t *dev = (ddc_t *) priv; - return ddc_read_byte_cmd(bus, addr, dev->addr_register++, priv); -} - - -uint16_t -ddc_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv) -{ - return (ddc_read_byte_cmd(bus, addr, cmd + 1, priv) << 8) | ddc_read_byte_cmd(bus, addr, cmd, priv); -} - - -uint8_t -ddc_read_block_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv) -{ - uint8_t read = 0; - for (uint8_t i = cmd; (i < len) && (i < 0x80); i++) - data[read++] = ddc_read_byte_cmd(bus, addr, i, priv); - return read; -} - - -void -ddc_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv) -{ - ddc_t *dev = (ddc_t *) priv; - dev->addr_register = val; -} - - -void +void * ddc_init(void *i2c) { - ddc_t *dev = (ddc_t *) malloc(sizeof(ddc_t)); - memset(dev, 0, sizeof(ddc_t)); - uint8_t checksum = 0; for (int c = 0; c < 127; c++) checksum += edid_data[c]; edid_data[127] = 256 - checksum; - i2c_sethandler(i2c, 0x50, 1, - NULL, ddc_read_byte, ddc_read_byte_cmd, ddc_read_word_cmd, ddc_read_block_cmd, - NULL, ddc_write_byte, NULL, NULL, NULL, - dev); + return i2c_eeprom_init(i2c, 0x50, edid_data, sizeof(edid_data), 0); +} + + +void +ddc_close(void *dev_handle) +{ + i2c_eeprom_close(dev_handle); } diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 7e24e9e77..cc5488a27 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -288,7 +288,7 @@ typedef struct virge_t uint8_t serialport; - void *i2c; + void *i2c, *ddc; } virge_t; static video_timings_t timing_diamond_stealth3d_2000_vlb = {VIDEO_BUS, 2, 2, 3, 28, 28, 45}; @@ -3849,7 +3849,7 @@ static void *s3_virge_init(const device_t *info) virge->fifo_thread = thread_create(fifo_thread, virge); virge->i2c = i2c_gpio_init("ddc_s3_virge"); - ddc_init(i2c_gpio_get_bus(virge->i2c)); + virge->ddc = ddc_init(i2c_gpio_get_bus(virge->i2c)); return virge; } @@ -3868,6 +3868,9 @@ static void s3_virge_close(void *p) thread_destroy_event(virge->fifo_not_full_event); svga_close(&virge->svga); + + ddc_close(virge->ddc); + i2c_gpio_close(virge->i2c); free(virge); } diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index dea6e2624..f7d04a790 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -118,7 +118,7 @@ typedef struct banshee_t int type; - void *i2c; + void *i2c, *ddc; } banshee_t; enum @@ -2629,7 +2629,7 @@ static void *banshee_init_common(const device_t *info, wchar_t *fn, int has_sgra banshee->vidSerialParallelPort = VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W; banshee->i2c = i2c_gpio_init("ddc_voodoo_banshee"); - ddc_init(i2c_gpio_get_bus(banshee->i2c)); + banshee->ddc = ddc_init(i2c_gpio_get_bus(banshee->i2c)); video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_banshee); @@ -2676,6 +2676,7 @@ static void banshee_close(void *p) voodoo_card_close(banshee->voodoo); svga_close(&banshee->svga); + ddc_close(banshee->ddc); i2c_gpio_close(banshee->i2c); free(banshee); diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index aaa2a3ad7..da113c811 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -654,7 +654,7 @@ MCHOBJ := machine.o machine_table.o \ DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \ lpt.o pci_bridge.o postcard.o serial.o vpc2007.o \ - i2c.o i2c_gpio.o smbus_piix4.o \ + i2c.o i2c_eeprom.o i2c_gpio.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o keyboard_at.o \ mouse.o \ From cf2dba5838a3ca877efdcdfcfcf53cd34d21ecf0 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 20 Nov 2020 19:33:22 -0300 Subject: [PATCH 03/16] De-duplicate VIA 586B I2C update code --- src/acpi.c | 22 ++++++++++++---------- src/device/hwm_gl518sm.c | 6 +++--- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index 06f2d87f0..ac5506ee6 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -649,6 +649,16 @@ acpi_reg_write_via_common(int size, uint16_t addr, uint8_t val, void *p) } +static void +acpi_i2c_set(acpi_t *dev) +{ + if (dev->i2c) { + /* Check direction as well due to pull-ups. */ + i2c_gpio_set(dev->i2c, !(dev->regs.gpio_dir & 0x02) || (dev->regs.gpio_val & 0x02), !(dev->regs.gpio_dir & 0x04) || (dev->regs.gpio_val & 0x04)); + } +} + + static void acpi_reg_write_via(int size, uint16_t addr, uint8_t val, void *p) { @@ -664,22 +674,14 @@ acpi_reg_write_via(int size, uint16_t addr, uint8_t val, void *p) /* GPIO Direction Control */ if (size == 1) { dev->regs.gpio_dir = val & 0x7f; - - if (dev->i2c) { - /* Check direction as well due to pull-ups. */ - i2c_gpio_set(dev->i2c, !(dev->regs.gpio_dir & 0x02) || (dev->regs.gpio_val & 0x02), !(dev->regs.gpio_dir & 0x04) || (dev->regs.gpio_val & 0x04)); - } + acpi_i2c_set(dev); } break; case 0x42: /* GPIO port Output Value */ if (size == 1) { dev->regs.gpio_val = val & 0x1f; - - if (dev->i2c) { - /* Check direction as well due to pull-ups. */ - i2c_gpio_set(dev->i2c, !(dev->regs.gpio_dir & 0x02) || (dev->regs.gpio_val & 0x02), !(dev->regs.gpio_dir & 0x04) || (dev->regs.gpio_val & 0x04)); - } + acpi_i2c_set(dev); } break; case 0x46: case 0x47: diff --git a/src/device/hwm_gl518sm.c b/src/device/hwm_gl518sm.c index 7ed1b0013..d0aeee193 100644 --- a/src/device/hwm_gl518sm.c +++ b/src/device/hwm_gl518sm.c @@ -76,7 +76,7 @@ gl518sm_log(const char *fmt, ...) static void gl518sm_remap(gl518sm_t *dev, uint8_t addr) { - gl518sm_log("GL518SM: remapping to I2C %02Xh\n", addr); + gl518sm_log("GL518SM: remapping to SMBus %02Xh\n", addr); i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, gl518sm_i2c_start, gl518sm_i2c_read, gl518sm_i2c_write, NULL, dev); @@ -284,7 +284,7 @@ gl518sm_init(const device_t *info) } -/* GL518SM on I2C address 2Ch */ +/* GL518SM on SMBus address 2Ch */ const device_t gl518sm_2c_device = { "Genesys Logic GL518SM Hardware Monitor", DEVICE_ISA, @@ -294,7 +294,7 @@ const device_t gl518sm_2c_device = { NULL }; -/* GL518SM on I2C address 2Dh */ +/* GL518SM on SMBus address 2Dh */ const device_t gl518sm_2d_device = { "Genesys Logic GL518SM Hardware Monitor", DEVICE_ISA, From d5867928d6a59874e2524fd2bb4211a74434d39e Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 21 Nov 2020 01:36:33 -0300 Subject: [PATCH 04/16] I2C overhaul part 3: "we finally figured out NCR NVRAM" edition --- src/device/hwm_gl518sm.c | 10 +- src/device/hwm_lm75.c | 105 ++++++++++--------- src/device/hwm_lm78.c | 2 +- src/device/i2c.c | 2 + src/device/i2c_eeprom.c | 58 ++++++++--- src/device/i2c_gpio.c | 57 +++++++++- src/scsi/scsi_ncr53c8xx.c | 213 ++++++++------------------------------ src/video/vid_ddc.c | 2 +- 8 files changed, 214 insertions(+), 235 deletions(-) diff --git a/src/device/hwm_gl518sm.c b/src/device/hwm_gl518sm.c index d0aeee193..33c9e6be3 100644 --- a/src/device/hwm_gl518sm.c +++ b/src/device/hwm_gl518sm.c @@ -103,13 +103,16 @@ gl518sm_i2c_read(void *bus, uint8_t addr, void *priv) uint16_t read = gl518sm_read(dev, dev->addr_register); uint8_t ret = 0; + if (dev->i2c_state == 0) + dev->i2c_state = 1; + if ((dev->i2c_state == 1) && (dev->addr_register >= 0x07) && (dev->addr_register <= 0x0c)) { /* two-byte registers: read MSB first */ dev->i2c_state = 2; ret = read >> 8; - } else + } else { ret = read; - - dev->addr_register++; + dev->addr_register++; + } return ret; } @@ -178,6 +181,7 @@ gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) break; default: + dev->i2c_state = 3; return 0; } diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index 8ee1aa06f..21d2b9b5c 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -35,7 +35,7 @@ static uint8_t lm75_i2c_read(void *bus, uint8_t addr, void *priv); static uint8_t lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv); static void lm75_reset(lm75_t *dev); - +#define ENABLE_LM75_LOG 1 #ifdef ENABLE_LM75_LOG int lm75_do_log = ENABLE_LM75_LOG; @@ -86,23 +86,39 @@ lm75_i2c_read(void *bus, uint8_t addr, void *priv) lm75_t *dev = (lm75_t *) priv; uint8_t ret = 0; - switch (dev->addr_register & 0x3) { - case 0x0: /* temperature */ - ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x1 : 0x0); - break; + if (dev->i2c_state == 0) + dev->i2c_state = 1; - case 0x1: /* configuration */ - ret = lm75_read(dev, 0x2); - break; + /* The AS99127F hardware monitor uses the addresses of its LM75 devices + to access some of its proprietary registers. Pass this operation on to + the main monitor address through an internal I2C call, if necessary. */ + if ((dev->addr_register > 0x7) && ((dev->addr_register & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) { + i2c_start(i2c_smbus, dev->as99127f_i2c_addr); + i2c_write(i2c_smbus, dev->as99127f_i2c_addr, dev->addr_register); + ret = i2c_read(i2c_smbus, dev->as99127f_i2c_addr); + i2c_stop(i2c_smbus, dev->as99127f_i2c_addr); + } else { + switch (dev->addr_register & 0x3) { + case 0x0: /* temperature */ + ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x0 : 0x1); + break; - case 0x2: /* Thyst */ - ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x4 : 0x3); - break; - case 0x3: /* Tos */ - ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x6 : 0x5); - break; + case 0x1: /* configuration */ + ret = lm75_read(dev, 0x2); + break; + + case 0x2: /* Thyst */ + ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x3 : 0x4); + break; + case 0x3: /* Tos */ + ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x5 : 0x6); + break; + } } + if (++dev->i2c_state > 2) + dev->i2c_state = 2; + return ret; } @@ -112,15 +128,7 @@ lm75_read(lm75_t *dev, uint8_t reg) { uint8_t ret; - /* The AS99127F hardware monitor uses the addresses of its LM75 devices - to access some of its proprietary registers. Pass this operation on to - the main monitor address through an internal I2C call, if necessary. */ - if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) { - i2c_start(i2c_smbus, dev->as99127f_i2c_addr); - i2c_write(i2c_smbus, dev->as99127f_i2c_addr, reg); - ret = i2c_read(i2c_smbus, dev->as99127f_i2c_addr); - i2c_stop(i2c_smbus, dev->as99127f_i2c_addr); - } else if ((reg & 0x7) == 0x0) /* temperature high byte */ + 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]); @@ -145,23 +153,37 @@ lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) return 1; } - switch (dev->addr_register & 0x3) { - case 0x0: /* temperature */ - lm75_write(dev, (dev->i2c_state == 1) ? 0x1 : 0x0, data); - break; + /* The AS99127F hardware monitor uses the addresses of its LM75 devices + to access some of its proprietary registers. Pass this operation on to + the main monitor address through an internal I2C call, if necessary. */ + if ((dev->addr_register > 0x7) && ((dev->addr_register & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) { + i2c_start(i2c_smbus, dev->as99127f_i2c_addr); + i2c_write(i2c_smbus, dev->as99127f_i2c_addr, dev->addr_register); + i2c_write(i2c_smbus, dev->as99127f_i2c_addr, data); + i2c_stop(i2c_smbus, dev->as99127f_i2c_addr); + return 1; + } else { + switch (dev->addr_register & 0x3) { + case 0x0: /* temperature */ + lm75_write(dev, (dev->i2c_state == 1) ? 0x0 : 0x1, data); + break; - case 0x1: /* configuration */ - lm75_write(dev, 0x2, data); - break; + case 0x1: /* configuration */ + lm75_write(dev, 0x2, data); + break; - case 0x2: /* Thyst */ - lm75_write(dev, (dev->i2c_state == 1) ? 0x4 : 0x3, data); - break; - case 0x3: /* Tos */ - lm75_write(dev, (dev->i2c_state == 1) ? 0x6 : 0x5, data); - break; + case 0x2: /* Thyst */ + lm75_write(dev, (dev->i2c_state == 1) ? 0x3 : 0x4, data); + break; + case 0x3: /* Tos */ + lm75_write(dev, (dev->i2c_state == 1) ? 0x5 : 0x6, data); + break; + } } + if (++dev->i2c_state > 2) + dev->i2c_state = 2; + return 1; } @@ -171,17 +193,6 @@ lm75_write(lm75_t *dev, uint8_t reg, uint8_t val) { lm75_log("LM75: write(%02X, %02X)\n", reg, val); - /* The AS99127F hardware monitor uses the addresses of its LM75 devices - to access some of its proprietary registers. Pass this operation on to - the main monitor address through an internal I2C call, if necessary. */ - if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) { - i2c_start(i2c_smbus, dev->as99127f_i2c_addr); - i2c_write(i2c_smbus, dev->as99127f_i2c_addr, reg); - i2c_write(i2c_smbus, dev->as99127f_i2c_addr, val); - i2c_stop(i2c_smbus, dev->as99127f_i2c_addr); - return 1; - } - uint8_t reg_idx = (reg & 0x7); if ((reg_idx <= 0x1) || (reg_idx == 0x7)) diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index 486e622c8..351fe7165 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -69,7 +69,7 @@ static uint8_t lm78_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank); static void lm78_reset(lm78_t *dev, uint8_t initialization); - +#define ENABLE_LM78_LOG 1 #ifdef ENABLE_LM78_LOG int lm78_do_log = ENABLE_LM78_LOG; diff --git a/src/device/i2c.c b/src/device/i2c.c index 7dabc9908..a4562deaf 100644 --- a/src/device/i2c.c +++ b/src/device/i2c.c @@ -194,6 +194,8 @@ i2c_has_device(void *bus_handle, uint8_t addr) if (!bus) return 0; + i2c_log("I2C: has_device(%s, %02X) = %d\n", bus->name, addr, !!bus->devices[addr]); + return(!!bus->devices[addr]); } diff --git a/src/device/i2c_eeprom.c b/src/device/i2c_eeprom.c index 7696955e8..dac00aeb2 100644 --- a/src/device/i2c_eeprom.c +++ b/src/device/i2c_eeprom.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * Emulation of the AT24Cxx series of I2C EEPROMs. + * Emulation of the 24Cxx series of I2C EEPROMs. * * * @@ -27,22 +27,42 @@ typedef struct { void *i2c; - uint8_t addr; - uint8_t *data; - uint8_t writable; + uint8_t addr, *data, writable; - uint16_t addr_mask; - uint8_t addr_register; + uint16_t addr_mask, addr_register; uint8_t i2c_state; } i2c_eeprom_t; +#define ENABLE_I2C_EEPROM_LOG 1 +#ifdef ENABLE_I2C_EEPROM_LOG +int i2c_eeprom_do_log = ENABLE_I2C_EEPROM_LOG; + + +static void +i2c_eeprom_log(const char *fmt, ...) +{ + va_list ap; + + if (i2c_eeprom_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define i2c_eeprom_log(fmt, ...) +#endif + void i2c_eeprom_start(void *bus, uint8_t addr, void *priv) { i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; + i2c_eeprom_log("I2C EEPROM: start()\n"); + dev->i2c_state = 0; + dev->addr_register = (addr << 8) & dev->addr_mask; } @@ -50,8 +70,13 @@ uint8_t i2c_eeprom_read(void *bus, uint8_t addr, void *priv) { i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; + uint8_t ret = dev->data[dev->addr_register]; - return dev->data[((addr << 8) | dev->addr_register++) & dev->addr_mask]; + i2c_eeprom_log("I2C EEPROM: read(%04X) = %02X\n", dev->addr_register, ret); + if (++dev->addr_register > dev->addr_mask) /* roll-over */ + dev->addr_register = 0; + + return ret; } @@ -62,11 +87,16 @@ i2c_eeprom_write(void *bus, uint8_t addr, uint8_t data, void *priv) if (dev->i2c_state == 0) { dev->i2c_state = 1; - dev->addr_register = data; - } else if (dev->writable) - dev->data[((addr << 8) | dev->addr_register++) & dev->addr_mask] = data; - else - return 0; + dev->addr_register = ((addr << 8) | data) & dev->addr_mask; + i2c_eeprom_log("I2C EEPROM: write(address, %04X)\n", dev->addr_register); + } else { + i2c_eeprom_log("I2C EEPROM: write(%04X, %02X) = %s\n", dev->addr_register, data, dev->writable ? "accepted" : "blocked"); + if (dev->writable) + dev->data[dev->addr_register] = data; + if (++dev->addr_register > dev->addr_mask) /* roll-over */ + dev->addr_register = 0; + return dev->writable; + } return 1; } @@ -78,6 +108,8 @@ i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint16_t size, uint8_t w i2c_eeprom_t *dev = (i2c_eeprom_t *) malloc(sizeof(i2c_eeprom_t)); memset(dev, 0, sizeof(i2c_eeprom_t)); + i2c_eeprom_log("I2C EEPROM: init(%02X, %d, %d)\n", addr, size, writable); + dev->i2c = i2c; dev->addr = addr; dev->data = data; @@ -96,6 +128,8 @@ i2c_eeprom_close(void *dev_handle) { i2c_eeprom_t *dev = (i2c_eeprom_t *) dev_handle; + i2c_eeprom_log("I2C EEPROM: close()\n"); + i2c_removehandler(dev->i2c, dev->addr & ~(dev->addr_mask >> 8), (dev->addr_mask >> 8) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev); free(dev); diff --git a/src/device/i2c_gpio.c b/src/device/i2c_gpio.c index e2b844200..aff3d1960 100644 --- a/src/device/i2c_gpio.c +++ b/src/device/i2c_gpio.c @@ -52,19 +52,43 @@ enum { }; typedef struct { + char *bus_name; void *i2c; uint8_t scl, sda, state, slave_state, slave_addr, slave_rw, last_sda, pos, transmit, byte; } i2c_gpio_t; +#ifdef ENABLE_I2C_GPIO_LOG +int i2c_gpio_do_log = ENABLE_I2C_GPIO_LOG; + + +static void +i2c_gpio_log(int level, const char *fmt, ...) +{ + va_list ap; + + if (i2c_gpio_do_log >= level) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define i2c_gpio_log(fmt, ...) +#endif + + void * i2c_gpio_init(char *bus_name) { i2c_gpio_t *dev = (i2c_gpio_t *) malloc(sizeof(i2c_gpio_t)); memset(dev, 0, sizeof(i2c_gpio_t)); - dev->i2c = i2c_addbus(bus_name); + i2c_gpio_log(1, "I2C GPIO %s: init()\n", bus_name); + + dev->bus_name = bus_name; + dev->i2c = i2c_addbus(dev->bus_name); dev->scl = dev->sda = 1; dev->slave_addr = 0xff; @@ -77,6 +101,8 @@ i2c_gpio_close(void *dev_handle) { i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; + i2c_gpio_log(1, "I2C GPIO %s: close()\n", dev->bus_name); + i2c_removebus(dev->i2c); free(dev); @@ -87,6 +113,7 @@ void i2c_gpio_next_byte(i2c_gpio_t *dev) { dev->byte = i2c_read(dev->i2c, dev->slave_addr); + i2c_gpio_log(1, "I2C GPIO %s: next_byte() = %02X\n", dev->bus_name, dev->byte); } @@ -101,6 +128,8 @@ i2c_gpio_write(i2c_gpio_t *dev) dev->slave_addr = dev->byte >> 1; dev->slave_rw = dev->byte & 1; + i2c_gpio_log(1, "I2C GPIO %s: Initiating transfer to address %02X rw %d\n", dev->bus_name, dev->slave_addr, dev->slave_rw); + if (!i2c_has_device(dev->i2c, dev->slave_addr)) { dev->slave_state = SLAVE_INVALID; break; @@ -120,11 +149,13 @@ i2c_gpio_write(i2c_gpio_t *dev) break; case SLAVE_RECEIVEADDR: + i2c_gpio_log(1, "I2C GPIO %s: Receiving address %02X\n", dev->bus_name, dev->byte); i2c_write(dev->i2c, dev->slave_addr, dev->byte); dev->slave_state = dev->slave_rw ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA; break; case SLAVE_RECEIVEDATA: + i2c_gpio_log(1, "I2C GPIO %s: Receiving data %02X\n", dev->bus_name, dev->byte); i2c_write(dev->i2c, dev->slave_addr, dev->byte); break; } @@ -134,7 +165,10 @@ i2c_gpio_write(i2c_gpio_t *dev) void i2c_gpio_stop(i2c_gpio_t *dev) { - i2c_stop(dev->i2c, dev->slave_addr); + i2c_gpio_log(1, "I2C GPIO %s: Stopping transfer\n", dev->bus_name); + + if (dev->slave_addr != 0xff) + i2c_stop(dev->i2c, dev->slave_addr); dev->slave_addr = 0xff; dev->slave_state = SLAVE_IDLE; @@ -149,7 +183,9 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) switch (dev->state) { case I2C_IDLE: - if (dev->scl && scl && dev->last_sda && !sda) { /* start bit */ + /* !dev->scl check breaks NCR SDMS. */ + if (/*!dev->scl &&*/ scl && dev->last_sda && !sda) { /* start bit */ + i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from IDLE)\n", dev->bus_name); dev->state = I2C_RECEIVE; dev->pos = 0; } @@ -173,9 +209,11 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) } } else if (dev->scl && scl) { if (sda && !dev->last_sda) { /* stop bit */ + i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from RECEIVE)\n", dev->bus_name); dev->state = I2C_IDLE; i2c_gpio_stop(dev); } else if (!sda && dev->last_sda) { /* start bit */ + i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from RECEIVE)\n", dev->bus_name); dev->pos = 0; dev->slave_state = SLAVE_IDLE; } @@ -184,6 +222,7 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) case I2C_ACKNOWLEDGE: if (!dev->scl && scl) { + i2c_gpio_log(2, "I2C GPIO %s: Acknowledging transfer\n", dev->bus_name); sda = 0; dev->pos = 0; dev->state = (dev->transmit == TRANSMITTER_MASTER) ? I2C_RECEIVE_WAIT : I2C_TRANSMIT; @@ -193,12 +232,14 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) case I2C_TRANSACKNOWLEDGE: if (!dev->scl && scl) { if (sda) { /* not acknowledged; must be end of transfer */ + i2c_gpio_log(2, "I2C GPIO %s: End of transfer\n", dev->bus_name); dev->state = I2C_IDLE; i2c_gpio_stop(dev); } else { /* next byte to transfer */ dev->state = I2C_TRANSMIT_START; i2c_gpio_next_byte(dev); dev->pos = 0; + i2c_gpio_log(2, "I2C GPIO %s: Next byte = %02X\n", dev->bus_name, dev->byte); } } break; @@ -208,8 +249,10 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) if (dev->last_sda && !sda) { /* start bit */ i2c_gpio_next_byte(dev); dev->pos = 0; + i2c_gpio_log(2, "I2C GPIO %s: Next byte = %02X\n", dev->bus_name, dev->byte); } if (!dev->last_sda && sda) { /* stop bit */ + i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from TRANSMIT_WAIT)\n", dev->bus_name); dev->state = I2C_IDLE; i2c_gpio_stop(dev); } @@ -220,6 +263,7 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) if (!dev->scl && scl) dev->state = I2C_TRANSMIT; if (dev->scl && scl && !dev->last_sda && sda) { /* stop bit */ + i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from TRANSMIT_START)\n", dev->bus_name); dev->state = I2C_IDLE; i2c_gpio_stop(dev); } @@ -228,13 +272,18 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) case I2C_TRANSMIT: if (!dev->scl && scl) { dev->scl = scl; + if (!dev->pos) + i2c_gpio_log(2, "I2C GPIO %s: Transmit byte %02X\n", dev->bus_name, dev->byte); dev->sda = sda = dev->byte & 0x80; + i2c_gpio_log(2, "I2C GPIO %s: Transmit bit %02X %d\n", dev->bus_name, dev->byte, dev->pos); dev->byte <<= 1; dev->pos++; return; } - if (dev->scl && !scl && (dev->pos == 8)) + if (dev->scl && !scl && (dev->pos == 8)) { dev->state = I2C_TRANSACKNOWLEDGE; + i2c_gpio_log(2, "I2C GPIO %s: Acknowledge mode\n", dev->bus_name); + } break; } diff --git a/src/scsi/scsi_ncr53c8xx.c b/src/scsi/scsi_ncr53c8xx.c index bb467781f..507bf339b 100644 --- a/src/scsi/scsi_ncr53c8xx.c +++ b/src/scsi/scsi_ncr53c8xx.c @@ -43,6 +43,7 @@ #include <86box/device.h> #include <86box/nvr.h> #include <86box/plat.h> +#include <86box/i2c.h> #include <86box/scsi.h> #include <86box/scsi_device.h> #include <86box/scsi_ncr53c8xx.h> @@ -225,14 +226,8 @@ typedef struct { int msg_action; int msg_len; uint8_t msg[NCR_MAX_MSGIN_LEN]; -#ifdef USE_NVRAM - uint16_t nvram; - uint8_t nvram_t; - uint8_t nvram_op; - uint8_t nvram_param; - uint8_t nvram_start; - uint8_t nvram_index; -#endif + uint8_t nvram[2048]; /* 24C16 EEPROM (16 kbit) */ + void *i2c, *eeprom; uint8_t ram[NCR_BUF_SIZE]; /* NCR 53c875 RAM (4 kB). */ /* 0 if SCRIPTS are running or stopped. * 1 if a Wait Reselect instruction has been issued. @@ -434,10 +429,7 @@ ncr53c8xx_soft_reset(ncr53c8xx_t *dev) dev->gpreg = 0; dev->slpar = 0; dev->sstop = 1; - dev->gpcntl = 0x0f; -#ifdef USE_NVRAM - dev->nvram_t = dev->nvram_index = 0; -#endif + dev->gpcntl = 0x03; if (dev->chip >= CHIP_825) { /* This *IS* a wide SCSI controller, so reset all SCSI @@ -474,7 +466,7 @@ ncr53c8xx_read(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) buf[i] = inb((uint16_t) (addr + i)); } else { ncr53c8xx_log("NCR 810: Reading from memory address %08X\n", addr); - dma_bm_read(addr, buf, len, 4); + dma_bm_read(addr, buf, len, 4); } } @@ -492,7 +484,7 @@ ncr53c8xx_write(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) outb((uint16_t) (addr + i), buf[i]); } else { ncr53c8xx_log("NCR 810: Writing to memory address %08X\n", addr); - dma_bm_write(addr, buf, len, 4); + dma_bm_write(addr, buf, len, 4); } } @@ -511,10 +503,10 @@ static void do_irq(ncr53c8xx_t *dev, int level) { if (level) { - pci_set_irq(dev->pci_slot, PCI_INTA); + pci_set_irq(dev->pci_slot, PCI_INTA); ncr53c8xx_log("Raising IRQ...\n"); } else { - pci_clear_irq(dev->pci_slot, PCI_INTA); + pci_clear_irq(dev->pci_slot, PCI_INTA); ncr53c8xx_log("Lowering IRQ...\n"); } } @@ -852,8 +844,8 @@ ncr53c8xx_do_msgin(ncr53c8xx_t *dev) switch to PHASE_MO. */ switch (dev->msg_action) { case 0: - ncr53c8xx_set_phase(dev, PHASE_CMD); - break; + ncr53c8xx_set_phase(dev, PHASE_CMD); + break; case 1: ncr53c8xx_disconnect(dev); break; @@ -1444,7 +1436,7 @@ ncr53c8xx_callback(void *p) if (dev->waiting) timer_on_auto(&dev->timer, 40.0); else - ncr53c8xx_process_script(dev); + ncr53c8xx_process_script(dev); } if (dev->sstop) @@ -1452,146 +1444,22 @@ ncr53c8xx_callback(void *p) } -#ifdef USE_NVRAM static void -ncr53c8xx_eeprom(ncr53c8xx_t *dev, int save) +ncr53c8xx_eeprom(ncr53c8xx_t *dev, uint8_t save) { FILE *f; - if (save) - f = nvr_fopen(dev->nvr_path, L"wb"); - else - f = nvr_fopen(dev->nvr_path, L"rb"); - if (f) - { - if (save) { - fwrite((uint8_t *) &dev->nvram, 1, 1, f); - fwrite(((uint8_t *) &dev->nvram) + 1, 1, 1, f); - } else { - fread((uint8_t *) &dev->nvram, 1, 1, f); - fread(((uint8_t *) &dev->nvram) + 1, 1, 1, f); - } + f = nvr_fopen(dev->nvr_path, save ? L"wb": L"rb"); + if (f) { + if (save) + fwrite(&dev->nvram, sizeof(dev->nvram), 1, f); + else + fread(&dev->nvram, sizeof(dev->nvram), 1, f); fclose(f); - f = NULL; } } -#define ADDRESS_LENGTH 9 -#define ADDRESS_END (ADDRESS_LENGTH + 2) -#define ADDRESS_SHIFT (ADDRESS_LENGTH - 2) -#define ADDRESS_MASK 0x3f -#define DATA_LENGTH 8 -#define DATA_START (ADDRESS_END + 1) -#define DATA_END (ADDRESS_END + DATA_LENGTH) - - -static void -ncr53c8xx_serial_eeprom_write(ncr53c8xx_t *dev, uint8_t val) -{ - uint8_t temp, old = dev->nvram_t; - dev->nvram_t = val & 0x03; - - if (val & 0x02) { - if (!dev->nvram_index) { - /* First signal clocked in after clock is high, start bit. */ - dev->nvram_start = 1; - ncr53c8xx_log("[W] Serial EEPROM: Start bit\n"); - dev->nvram_op = 0; - } else if ((dev->nvram_index == 1) || (dev->nvram_index == 2)) { - if (!dev->nvram_start) - return; - - dev->nvram_op = (val & 0x01) << (dev->nvram_index - 1); - if (dev->nvram_index == 2) { - // ncr53c8xx_log("[W] Serial EEPROM: Opcode: %01X\n", dev->nvram_op); - dev->nvram_param = 0; - } - } else if ((dev->nvram_index >= 3) && (dev->nvram_index <= ADDRESS_END)) { - if (!dev->nvram_start) - return; - - dev->nvram_param = (val & 0x01) << (dev->nvram_index - 3); - if (dev->nvram_index < ADDRESS_END) { - dev->nvram_index++; - return; - } - - switch (dev->nvram_op) { - case 0x00: - temp = dev->nvram_param >> ADDRESS_SHIFT; - switch(temp) { - case 0x00: - ncr53c8xx_log("[W] Serial EEPROM: EWDS\n"); - break; - case 0x01: - ncr53c8xx_log("[W] Serial EEPROM: WRAL\n"); - break; - case 0x02: - ncr53c8xx_log("[W] Serial EEPROM: ERAL\n"); - break; - case 0x03: - ncr53c8xx_log("[W] Serial EEPROM: EWEN\n"); - break; - default: - ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN 00\n"); - break; - } - dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; - return; - case 0x01: - ncr53c8xx_log("[W] Serial EEPROM: WRITE\n"); - break; - case 0x02: - ncr53c8xx_log("[W] Serial EEPROM: READ\n"); - break; - case 0x03: - ncr53c8xx_log("[W] Serial EEPROM: ERASE\n"); - break; - default: - ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN\n"); - break; - } - } else if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) { - if (!dev->nvram_start) - return; - - if (dev->nvram_index == DATA_END) { - ncr53c8xx_log("[W] Serial EEPROM: Data end\n"); - dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; - return; - } - } - dev->nvram_index++; - } -} - - -static uint8_t -ncr53c8xx_serial_eeprom_read(ncr53c8xx_t *dev) -{ - uint8_t temp = 0; - - if (dev->gpreg & 0x02) { - if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) { - if (!dev->nvram_start) - return temp; - - dev->nvram_index++; - - if (dev->nvram_index == DATA_END) { - ncr53c8xx_log("[R] Serial EEPROM: Data end\n"); - dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; - return temp; - } - } - } - - return temp; -} -#endif - - static void ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val) { @@ -1659,12 +1527,8 @@ ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val) break; case 0x07: /* GPREG */ ncr53c8xx_log("NCR 810: GPREG write %02X\n", val); - tmp = dev->gpreg; - dev->gpreg = val & 0xfe; -#ifdef USE_NVRAM - if ((dev->gpcntl & 0xc3) == 0x00) - ncr53c8xx_serial_eeprom_write(dev, val & 0x03); -#endif + dev->gpreg = val; + i2c_gpio_set(dev->i2c, !!(dev->gpreg & 0x02), !!(dev->gpreg & 0x01)); break; case 0x08: /* SFBR */ /* The CPU is not allowed to write to this register. However the @@ -1893,13 +1757,18 @@ ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset) ncr53c8xx_log("NCR 810: Read SDID %02X\n", dev->sdid); return dev->sdid; case 0x07: /* GPREG */ -#ifdef USE_NVRAM - tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e; - if ((dev->gpcntl & 0xc3) == 0x01) - tmp |= ncr53c8xx_serial_eeprom_read(dev); -#else - tmp = ((dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e) | 0x01; -#endif + tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1f; + if ((dev->gpcntl & 0x41) == 0x01) { + tmp &= 0xfe; + if (i2c_gpio_get_sda(dev->i2c)) + tmp |= 0x01; + } + if ((dev->gpcntl & 0x82) == 0x02) { + tmp &= 0xfd; + if (i2c_gpio_get_scl(dev->i2c)) + tmp |= 0x02; + } + ncr53c8xx_log("NCR 810: Read GPREG %02X\n", tmp); return tmp; case 0x08: /* Revision ID */ @@ -2677,8 +2546,8 @@ ncr53c8xx_init(const device_t *info) dev->chip_rev = 0x26; dev->nvr_path = L"ncr53c825a.nvr"; } - ncr53c8xx_pci_bar[2].addr_regs[0] = 0; - ncr53c8xx_pci_bar[3].addr = 0xffff0000; + ncr53c8xx_pci_bar[2].addr_regs[0] = 0; + ncr53c8xx_pci_bar[3].addr = 0xffff0000; /* Need to make it align on a 16k boundary as that's this emulator's memory mapping granularity. */ ncr53c8xx_ram_init(dev, 0x0fffc000); @@ -2695,10 +2564,11 @@ ncr53c8xx_init(const device_t *info) dev->nvr_path = L"ncr53c810.nvr"; } -#ifdef USE_NVRAM + dev->i2c = i2c_gpio_init("nvr_ncr53c8xx"); + dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->nvram, sizeof(dev->nvram), 1); + /* Load the serial EEPROM. */ ncr53c8xx_eeprom(dev, 0); -#endif ncr53c8xx_soft_reset(dev); @@ -2714,6 +2584,15 @@ ncr53c8xx_close(void *priv) ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; if (dev) { + /* Save the serial EEPROM. */ + ncr53c8xx_eeprom(dev, 1); + + if (dev->eeprom) + i2c_eeprom_close(dev->eeprom); + + if (dev->i2c) + i2c_gpio_close(dev->i2c); + free(dev); dev = NULL; } diff --git a/src/video/vid_ddc.c b/src/video/vid_ddc.c index 45788842e..f84d790e9 100644 --- a/src/video/vid_ddc.c +++ b/src/video/vid_ddc.c @@ -38,7 +38,7 @@ static uint8_t edid_data[128] = { 0x08, /* Analog input, separate sync */ 34, 0, /* Landscape, 4:3 */ 0, /* Gamma */ - 0x08, /* RGB colour */ + 0x08, /* RGB color */ 0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /* Chromaticity */ 0xff, 0xff, 0xff, /* Established timing bitmap */ From 3fb4727483faede452f9e669173b41a44a3dfa74 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 22 Nov 2020 00:19:13 -0300 Subject: [PATCH 05/16] I2C overhaul part 4: VIA and EEPROM edition --- src/acpi.c | 2 +- src/chipset/via_pipc.c | 4 +- src/device/hwm_gl518sm.c | 12 +- src/device/hwm_lm75.c | 22 ++-- src/device/hwm_lm78.c | 10 +- src/device/i2c.c | 56 +++++++--- src/device/i2c_eeprom.c | 49 +++++---- src/device/i2c_gpio.c | 74 ++++++++----- src/device/smbus_piix4.c | 188 +++++++++++++++++++++++++------- src/include/86box/i2c.h | 11 +- src/include/86box/smbus_piix4.h | 14 ++- 11 files changed, 313 insertions(+), 129 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index ac5506ee6..cb1f4d91f 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -653,7 +653,7 @@ static void acpi_i2c_set(acpi_t *dev) { if (dev->i2c) { - /* Check direction as well due to pull-ups. */ + /* Check direction as well to account for the I2C pull-ups. */ i2c_gpio_set(dev->i2c, !(dev->regs.gpio_dir & 0x02) || (dev->regs.gpio_val & 0x02), !(dev->regs.gpio_dir & 0x04) || (dev->regs.gpio_val & 0x04)); } } diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index bbf82e083..5ff1d5e3b 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -868,7 +868,9 @@ pipc_init(const device_t *info) dev->nvr = device_add(&via_nvr_device); - if (dev->local >= VIA_PIPC_596A) + if (dev->local >= VIA_PIPC_686B) + dev->smbus = device_add(&via_smbus_device); + else if (dev->local >= VIA_PIPC_596A) dev->smbus = device_add(&piix4_smbus_device); if (dev->local >= VIA_PIPC_596A) diff --git a/src/device/hwm_gl518sm.c b/src/device/hwm_gl518sm.c index 33c9e6be3..f56b803ea 100644 --- a/src/device/hwm_gl518sm.c +++ b/src/device/hwm_gl518sm.c @@ -45,7 +45,7 @@ typedef struct { } gl518sm_t; -static void gl518sm_i2c_start(void *bus, uint8_t addr, void *priv); +static uint8_t gl518sm_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv); static uint8_t gl518sm_i2c_read(void *bus, uint8_t addr, void *priv); static uint16_t gl518sm_read(gl518sm_t *dev, uint8_t reg); static uint8_t gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv); @@ -87,12 +87,14 @@ gl518sm_remap(gl518sm_t *dev, uint8_t addr) } -static void -gl518sm_i2c_start(void *bus, uint8_t addr, void *priv) +static uint8_t +gl518sm_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv) { gl518sm_t *dev = (gl518sm_t *) priv; dev->i2c_state = 0; + + return 1; } @@ -173,11 +175,11 @@ gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) break; case 1: - gl518sm_write(dev, dev->addr_register, data); + gl518sm_write(dev, dev->addr_register, (gl518sm_read(dev, dev->addr_register) & 0xff00) | data); break; case 2: - gl518sm_write(dev, dev->addr_register, (data << 8) | gl518sm_read(dev, dev->addr_register)); + gl518sm_write(dev, dev->addr_register, (gl518sm_read(dev, dev->addr_register) << 8) | data); break; default: diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index 21d2b9b5c..fdb9149ae 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -30,7 +30,7 @@ #define LM75_TEMP_TO_REG(t) ((t) << 8) -static void lm75_i2c_start(void *bus, uint8_t addr, void *priv); +static uint8_t lm75_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv); static uint8_t lm75_i2c_read(void *bus, uint8_t addr, void *priv); static uint8_t lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv); static void lm75_reset(lm75_t *dev); @@ -59,7 +59,7 @@ lm75_log(const char *fmt, ...) void lm75_remap(lm75_t *dev, uint8_t addr) { - lm75_log("LM75: remapping to I2C %02Xh\n", addr); + lm75_log("LM75: remapping to SMBus %02Xh\n", addr); if (dev->i2c_addr < 0x80) i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, lm75_i2c_start, lm75_i2c_read, lm75_i2c_write, NULL, dev); @@ -71,12 +71,14 @@ lm75_remap(lm75_t *dev, uint8_t addr) } -static void -lm75_i2c_start(void *bus, uint8_t addr, void *priv) +static uint8_t +lm75_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv) { lm75_t *dev = (lm75_t *) priv; dev->i2c_state = 0; + + return 1; } @@ -93,7 +95,7 @@ lm75_i2c_read(void *bus, uint8_t addr, void *priv) to access some of its proprietary registers. Pass this operation on to the main monitor address through an internal I2C call, if necessary. */ if ((dev->addr_register > 0x7) && ((dev->addr_register & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) { - i2c_start(i2c_smbus, dev->as99127f_i2c_addr); + i2c_start(i2c_smbus, dev->as99127f_i2c_addr, 1); i2c_write(i2c_smbus, dev->as99127f_i2c_addr, dev->addr_register); ret = i2c_read(i2c_smbus, dev->as99127f_i2c_addr); i2c_stop(i2c_smbus, dev->as99127f_i2c_addr); @@ -149,7 +151,10 @@ lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) if ((dev->i2c_state > 2) || ((dev->i2c_state == 2) && ((dev->addr_register & 0x3) == 0x1))) { return 0; } else if (dev->i2c_state == 0) { - dev->addr_register = data; + dev->i2c_state = 1; + /* Linux lm75.c driver relies on a 3-bit address register that doesn't change if bit 2 is set. */ + if ((dev->as99127f_i2c_addr >= 0x80) && !(data & 0x04)) + dev->addr_register = (data & 0x7); return 1; } @@ -157,7 +162,7 @@ lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) to access some of its proprietary registers. Pass this operation on to the main monitor address through an internal I2C call, if necessary. */ if ((dev->addr_register > 0x7) && ((dev->addr_register & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) { - i2c_start(i2c_smbus, dev->as99127f_i2c_addr); + i2c_start(i2c_smbus, dev->as99127f_i2c_addr, 0); i2c_write(i2c_smbus, dev->as99127f_i2c_addr, dev->addr_register); i2c_write(i2c_smbus, dev->as99127f_i2c_addr, data); i2c_stop(i2c_smbus, dev->as99127f_i2c_addr); @@ -175,13 +180,14 @@ lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) case 0x2: /* Thyst */ lm75_write(dev, (dev->i2c_state == 1) ? 0x3 : 0x4, data); break; + case 0x3: /* Tos */ lm75_write(dev, (dev->i2c_state == 1) ? 0x5 : 0x6, data); break; } } - if (++dev->i2c_state > 2) + if (dev->i2c_state == 1) dev->i2c_state = 2; return 1; diff --git a/src/device/hwm_lm78.c b/src/device/hwm_lm78.c index 351fe7165..ad4cb7425 100644 --- a/src/device/hwm_lm78.c +++ b/src/device/hwm_lm78.c @@ -60,7 +60,7 @@ typedef struct { } lm78_t; -static void lm78_i2c_start(void *bus, uint8_t addr, void *priv); +static uint8_t lm78_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv); static uint8_t lm78_isa_read(uint16_t port, void *priv); static uint8_t lm78_i2c_read(void *bus, uint8_t addr, void *priv); static uint8_t lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank); @@ -69,7 +69,7 @@ static uint8_t lm78_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank); static void lm78_reset(lm78_t *dev, uint8_t initialization); -#define ENABLE_LM78_LOG 1 + #ifdef ENABLE_LM78_LOG int lm78_do_log = ENABLE_LM78_LOG; @@ -118,12 +118,14 @@ lm78_remap(lm78_t *dev, uint8_t addr) } -static void -lm78_i2c_start(void *bus, uint8_t addr, void *priv) +static uint8_t +lm78_i2c_start(void *bus, uint8_t addr, uint8_t read, void *priv) { lm78_t *dev = (lm78_t *) priv; dev->i2c_state = 0; + + return 1; } diff --git a/src/device/i2c.c b/src/device/i2c.c index a4562deaf..75ec557ab 100644 --- a/src/device/i2c.c +++ b/src/device/i2c.c @@ -30,7 +30,7 @@ typedef struct _i2c_ { - void (*start)(void *bus, uint8_t addr, void *priv); + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv); uint8_t (*read)(void *bus, uint8_t addr, void *priv); uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv); void (*stop)(void *bus, uint8_t addr, void *priv); @@ -84,16 +84,43 @@ i2c_addbus(char *name) void i2c_removebus(void *bus_handle) { + int c; + i2c_t *p, *q; + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + if (!bus_handle) return; - free(bus_handle); + for (c = 0; c < NADDRS; c++) { + p = bus->devices[c]; + if (!p) + continue; + while(p) { + q = p->next; + free(p); + p = q; + } + } + + free(bus); +} + + +char * +i2c_getbusname(void *bus_handle) +{ + i2c_bus_t *bus = (i2c_bus_t *) bus_handle; + + if (!bus_handle) + return; + + return(bus->name); } void i2c_sethandler(void *bus_handle, uint8_t base, int size, - void (*start)(void *bus, uint8_t addr, void *priv), + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv), uint8_t (*read)(void *bus, uint8_t addr, void *priv), uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), void (*stop)(void *bus, uint8_t addr, void *priv), @@ -103,7 +130,7 @@ i2c_sethandler(void *bus_handle, uint8_t base, int size, i2c_t *p, *q = NULL; i2c_bus_t *bus = (i2c_bus_t *) bus_handle; - if (!bus_handle || ((base + size) >= NADDRS)) + if (!bus_handle || ((base + size) > NADDRS)) return; for (c = 0; c < size; c++) { @@ -133,7 +160,7 @@ i2c_sethandler(void *bus_handle, uint8_t base, int size, void i2c_removehandler(void *bus_handle, uint8_t base, int size, - void (*start)(void *bus, uint8_t addr, void *priv), + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv), uint8_t (*read)(void *bus, uint8_t addr, void *priv), uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), void (*stop)(void *bus, uint8_t addr, void *priv), @@ -143,7 +170,7 @@ i2c_removehandler(void *bus_handle, uint8_t base, int size, i2c_t *p, *q; i2c_bus_t *bus = (i2c_bus_t *) bus_handle; - if (!bus_handle || ((base + size) >= NADDRS)) + if (!bus_handle || ((base + size) > NADDRS)) return; for (c = 0; c < size; c++) { @@ -152,7 +179,7 @@ i2c_removehandler(void *bus_handle, uint8_t base, int size, continue; while(p) { q = p->next; - if ((p->read == read) && (p->write == write) && (p->priv == priv)) { + if ((p->start == start) && (p->read == read) && (p->write == write) && (p->stop == stop) && (p->priv == priv)) { if (p->prev) p->prev->next = p->next; else @@ -173,7 +200,7 @@ i2c_removehandler(void *bus_handle, uint8_t base, int size, void i2c_handler(int set, void *bus_handle, uint8_t base, int size, - void (*start)(void *bus, uint8_t addr, void *priv), + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv), uint8_t (*read)(void *bus, uint8_t addr, void *priv), uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), void (*stop)(void *bus, uint8_t addr, void *priv), @@ -200,26 +227,29 @@ i2c_has_device(void *bus_handle, uint8_t addr) } -void -i2c_start(void *bus_handle, uint8_t addr) +uint8_t +i2c_start(void *bus_handle, uint8_t addr, uint8_t read) { + uint8_t ret = 0; i2c_bus_t *bus = (i2c_bus_t *) bus_handle; i2c_t *p; if (!bus) - return; + return(ret); p = bus->devices[addr]; if (p) { while(p) { if (p->start) { - p->start(bus_handle, addr, p->priv); + ret |= p->start(bus_handle, addr, read, p->priv); } p = p->next; } } i2c_log("I2C: start(%s, %02X)\n", bus->name, addr); + + return(ret); } @@ -264,7 +294,7 @@ i2c_write(void *bus_handle, uint8_t addr, uint8_t data) if (p) { while(p) { if (p->write) { - ret = p->write(bus_handle, addr, data, p->priv); + ret |= p->write(bus_handle, addr, data, p->priv); } p = p->next; } diff --git a/src/device/i2c_eeprom.c b/src/device/i2c_eeprom.c index dac00aeb2..02e738c89 100644 --- a/src/device/i2c_eeprom.c +++ b/src/device/i2c_eeprom.c @@ -29,11 +29,11 @@ typedef struct { void *i2c; uint8_t addr, *data, writable; - uint16_t addr_mask, addr_register; - uint8_t i2c_state; + uint32_t addr_mask, addr_register; + uint8_t addr_len, addr_pos; } i2c_eeprom_t; -#define ENABLE_I2C_EEPROM_LOG 1 + #ifdef ENABLE_I2C_EEPROM_LOG int i2c_eeprom_do_log = ENABLE_I2C_EEPROM_LOG; @@ -54,15 +54,17 @@ i2c_eeprom_log(const char *fmt, ...) #endif -void -i2c_eeprom_start(void *bus, uint8_t addr, void *priv) +uint8_t +i2c_eeprom_start(void *bus, uint8_t addr, uint8_t read, void *priv) { i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; - i2c_eeprom_log("I2C EEPROM: start()\n"); + i2c_eeprom_log("I2C EEPROM %s %02X: start()\n", i2c_getbusname(dev->i2c), dev->addr); - dev->i2c_state = 0; - dev->addr_register = (addr << 8) & dev->addr_mask; + dev->addr_pos = 0; + dev->addr_register = (addr << dev->addr_len) & dev->addr_mask; + + return 1; } @@ -72,7 +74,7 @@ i2c_eeprom_read(void *bus, uint8_t addr, void *priv) i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; uint8_t ret = dev->data[dev->addr_register]; - i2c_eeprom_log("I2C EEPROM: read(%04X) = %02X\n", dev->addr_register, ret); + i2c_eeprom_log("I2C EEPROM %s %02X: read(%06X) = %02X\n", i2c_getbusname(dev->i2c), dev->addr, dev->addr_register, ret); if (++dev->addr_register > dev->addr_mask) /* roll-over */ dev->addr_register = 0; @@ -85,13 +87,17 @@ i2c_eeprom_write(void *bus, uint8_t addr, uint8_t data, void *priv) { i2c_eeprom_t *dev = (i2c_eeprom_t *) priv; - if (dev->i2c_state == 0) { - dev->i2c_state = 1; - dev->addr_register = ((addr << 8) | data) & dev->addr_mask; - i2c_eeprom_log("I2C EEPROM: write(address, %04X)\n", dev->addr_register); + if (dev->addr_pos < dev->addr_len) { + dev->addr_register <<= 8; + dev->addr_register |= data; + dev->addr_register &= (1 << dev->addr_len) - 1; + dev->addr_register |= addr << dev->addr_len; + dev->addr_register &= dev->addr_mask; + i2c_eeprom_log("I2C EEPROM %s %02X: write(address, %04X)\n", i2c_getbusname(dev->i2c), dev->addr, dev->addr_register); + dev->addr_pos += 8; } else { - i2c_eeprom_log("I2C EEPROM: write(%04X, %02X) = %s\n", dev->addr_register, data, dev->writable ? "accepted" : "blocked"); - if (dev->writable) + i2c_eeprom_log("I2C EEPROM %s %02X: write(%06X, %02X) = %d\n", i2c_getbusname(dev->i2c), dev->addr, dev->addr_register, data, !!dev->writable); + if (dev->writable) dev->data[dev->addr_register] = data; if (++dev->addr_register > dev->addr_mask) /* roll-over */ dev->addr_register = 0; @@ -103,21 +109,24 @@ i2c_eeprom_write(void *bus, uint8_t addr, uint8_t data, void *priv) void * -i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint16_t size, uint8_t writable) +i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint32_t size, uint8_t writable) { i2c_eeprom_t *dev = (i2c_eeprom_t *) malloc(sizeof(i2c_eeprom_t)); memset(dev, 0, sizeof(i2c_eeprom_t)); - i2c_eeprom_log("I2C EEPROM: init(%02X, %d, %d)\n", addr, size, writable); + size &= 0x7fffff; /* address space limit of 8 MB = 7 bits from I2C address + 16 bits */ + + i2c_eeprom_log("I2C EEPROM %s %02X: init(%d, %d)\n", i2c_getbusname(i2c), addr, size, writable); dev->i2c = i2c; dev->addr = addr; dev->data = data; dev->writable = writable; + dev->addr_len = (size >= 4096) ? 16 : 8; /* use 16-bit addresses on 24C32 and above */ dev->addr_mask = size - 1; - i2c_sethandler(i2c, dev->addr & ~(dev->addr_mask >> 8), (dev->addr_mask >> 8) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev); + i2c_sethandler(i2c, dev->addr & ~(dev->addr_mask >> dev->addr_len), (dev->addr_mask >> dev->addr_len) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev); return dev; } @@ -128,9 +137,9 @@ i2c_eeprom_close(void *dev_handle) { i2c_eeprom_t *dev = (i2c_eeprom_t *) dev_handle; - i2c_eeprom_log("I2C EEPROM: close()\n"); + i2c_eeprom_log("I2C EEPROM %s %02X: close()\n", i2c_getbusname(dev->i2c), dev->addr); - i2c_removehandler(dev->i2c, dev->addr & ~(dev->addr_mask >> 8), (dev->addr_mask >> 8) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev); + i2c_removehandler(dev->i2c, dev->addr & ~(dev->addr_mask >> dev->addr_len), (dev->addr_mask >> dev->addr_len) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev); free(dev); } diff --git a/src/device/i2c_gpio.c b/src/device/i2c_gpio.c index aff3d1960..bca2e4a1e 100644 --- a/src/device/i2c_gpio.c +++ b/src/device/i2c_gpio.c @@ -39,6 +39,7 @@ enum { I2C_TRANSMIT_START, I2C_TRANSMIT, I2C_ACKNOWLEDGE, + I2C_NEGACKNOWLEDGE, I2C_TRANSACKNOWLEDGE, I2C_TRANSMIT_WAIT }; @@ -55,7 +56,7 @@ typedef struct { char *bus_name; void *i2c; uint8_t scl, sda, state, slave_state, slave_addr, - slave_rw, last_sda, pos, transmit, byte; + slave_read, last_sda, pos, transmit, byte; } i2c_gpio_t; @@ -113,11 +114,11 @@ void i2c_gpio_next_byte(i2c_gpio_t *dev) { dev->byte = i2c_read(dev->i2c, dev->slave_addr); - i2c_gpio_log(1, "I2C GPIO %s: next_byte() = %02X\n", dev->bus_name, dev->byte); + i2c_gpio_log(1, "I2C GPIO %s: Transmitting data %02X\n", dev->bus_name, dev->byte); } -void +uint8_t i2c_gpio_write(i2c_gpio_t *dev) { uint8_t i; @@ -126,19 +127,20 @@ i2c_gpio_write(i2c_gpio_t *dev) case SLAVE_IDLE: i = dev->slave_addr; dev->slave_addr = dev->byte >> 1; - dev->slave_rw = dev->byte & 1; + dev->slave_read = dev->byte & 1; - i2c_gpio_log(1, "I2C GPIO %s: Initiating transfer to address %02X rw %d\n", dev->bus_name, dev->slave_addr, dev->slave_rw); + i2c_gpio_log(1, "I2C GPIO %s: Initiating %s address %02X\n", dev->bus_name, dev->slave_read ? "read from" : "write to", dev->slave_addr); if (!i2c_has_device(dev->i2c, dev->slave_addr)) { dev->slave_state = SLAVE_INVALID; - break; + dev->slave_addr = 0xff; + return I2C_NEGACKNOWLEDGE; } - if (i == 0xff) - i2c_start(dev->i2c, dev->slave_addr); + if (i == 0xff) /* start only once per transfer */ + i2c_start(dev->i2c, dev->slave_addr, dev->slave_read); - if (dev->slave_rw) { + if (dev->slave_read) { dev->slave_state = SLAVE_SENDDATA; dev->transmit = TRANSMITTER_SLAVE; dev->byte = i2c_read(dev->i2c, dev->slave_addr); @@ -150,15 +152,22 @@ i2c_gpio_write(i2c_gpio_t *dev) case SLAVE_RECEIVEADDR: i2c_gpio_log(1, "I2C GPIO %s: Receiving address %02X\n", dev->bus_name, dev->byte); - i2c_write(dev->i2c, dev->slave_addr, dev->byte); - dev->slave_state = dev->slave_rw ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA; + dev->slave_state = dev->slave_read ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA; + if (!i2c_write(dev->i2c, dev->slave_addr, dev->byte)) + return I2C_NEGACKNOWLEDGE; break; case SLAVE_RECEIVEDATA: i2c_gpio_log(1, "I2C GPIO %s: Receiving data %02X\n", dev->bus_name, dev->byte); - i2c_write(dev->i2c, dev->slave_addr, dev->byte); + if (!i2c_write(dev->i2c, dev->slave_addr, dev->byte)) + return I2C_NEGACKNOWLEDGE; break; + + case SLAVE_INVALID: + return I2C_NEGACKNOWLEDGE; } + + return I2C_ACKNOWLEDGE; } @@ -167,7 +176,7 @@ i2c_gpio_stop(i2c_gpio_t *dev) { i2c_gpio_log(1, "I2C GPIO %s: Stopping transfer\n", dev->bus_name); - if (dev->slave_addr != 0xff) + if (dev->slave_addr != 0xff) /* don't stop if no transfer was in progress */ i2c_stop(dev->i2c, dev->slave_addr); dev->slave_addr = 0xff; @@ -183,8 +192,8 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) switch (dev->state) { case I2C_IDLE: - /* !dev->scl check breaks NCR SDMS. */ - if (/*!dev->scl &&*/ scl && dev->last_sda && !sda) { /* start bit */ + /* dev->scl check breaks NCR SDMS. */ + if (scl && dev->last_sda && !sda) { /* start bit */ i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from IDLE)\n", dev->bus_name); dev->state = I2C_RECEIVE; dev->pos = 0; @@ -203,10 +212,8 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) dev->byte |= 1; else dev->byte &= 0xfe; - if (++dev->pos == 8) { - i2c_gpio_write(dev); - dev->state = I2C_ACKNOWLEDGE; - } + if (++dev->pos == 8) + dev->state = i2c_gpio_write(dev); } else if (dev->scl && scl) { if (sda && !dev->last_sda) { /* stop bit */ i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from RECEIVE)\n", dev->bus_name); @@ -222,13 +229,23 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) case I2C_ACKNOWLEDGE: if (!dev->scl && scl) { - i2c_gpio_log(2, "I2C GPIO %s: Acknowledging transfer\n", dev->bus_name); + i2c_gpio_log(2, "I2C GPIO %s: Acknowledging transfer to %02X\n", dev->bus_name, dev->slave_addr); sda = 0; dev->pos = 0; dev->state = (dev->transmit == TRANSMITTER_MASTER) ? I2C_RECEIVE_WAIT : I2C_TRANSMIT; } break; + case I2C_NEGACKNOWLEDGE: + if (!dev->scl && scl) { + i2c_gpio_log(2, "I2C GPIO %s: Nacking transfer\n", dev->bus_name); + sda = 1; + dev->pos = 0; + dev->state = I2C_IDLE; + dev->slave_state = SLAVE_IDLE; + } + break; + case I2C_TRANSACKNOWLEDGE: if (!dev->scl && scl) { if (sda) { /* not acknowledged; must be end of transfer */ @@ -306,12 +323,17 @@ uint8_t i2c_gpio_get_sda(void *dev_handle) { i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; - if ((dev->state == I2C_TRANSMIT) || (dev->state == I2C_ACKNOWLEDGE)) - return dev->sda; - else if (dev->state == I2C_RECEIVE_WAIT) - return 0; /* ack */ - else - return 1; + switch (dev->state) { + case I2C_TRANSMIT: + case I2C_ACKNOWLEDGE: + return dev->sda; + + case I2C_RECEIVE_WAIT: + return 0; /* ack */ + + default: + return 1; + } } diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index 100a31ab8..ae41347f6 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -98,95 +98,189 @@ static void smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) { smbus_piix4_t *dev = (smbus_piix4_t *) priv; - uint8_t smbus_addr, smbus_read, prev_stat; + uint8_t smbus_addr, cmd, read, block_len, prev_stat, timer_bytes = 0; smbus_piix4_log("SMBus PIIX4: write(%02X, %02X)\n", addr, val); prev_stat = dev->next_stat; - dev->next_stat = 0; + dev->next_stat = 0x00; switch (addr - dev->io_base) { case 0x00: - /* some status bits are reset by writing 1 to them */ - for (smbus_addr = 0x02; smbus_addr <= 0x10; smbus_addr <<= 1) { + for (smbus_addr = 0x02; smbus_addr <= 0x10; smbus_addr <<= 1) { /* handle clearable bits */ if (val & smbus_addr) dev->stat &= ~smbus_addr; } break; case 0x02: - dev->ctl = val & ~(0x40); /* START always reads 0 */ + dev->ctl = val & ((dev->local == SMBUS_VIA) ? 0x3f : 0x1f); if (val & 0x02) { /* cancel an in-progress command if KILL is set */ - /* cancel only if a command is in progress */ - if (prev_stat) { - dev->stat = 0x10; /* raise FAILED */ + if (prev_stat) { /* cancel only if a command is in progress */ timer_disable(&dev->response_timer); + dev->stat = 0x10; /* raise FAILED */ } } if (val & 0x40) { /* dispatch command if START is set */ + timer_bytes++; /* address */ + smbus_addr = (dev->addr >> 1); - if (!i2c_has_device(i2c_smbus, smbus_addr)) { - /* raise DEV_ERR if no device is at this address */ - dev->next_stat = 0x4; + read = dev->addr & 0x01; + + /* Raise DEV_ERR if no device is at this address, or if the device returned NAK when starting the transfer. */ + if (!i2c_has_device(i2c_smbus, smbus_addr) || !i2c_start(i2c_smbus, smbus_addr, read)) { + dev->next_stat = 0x04; break; } - smbus_read = dev->addr & 0x01; - /* start transaction */ - i2c_start(i2c_smbus, smbus_addr); + dev->next_stat = 0x02; /* raise INTER (command completed) by default */ - /* decode the 3-bit command protocol */ - dev->next_stat = 0x2; /* raise INTER (command completed) by default */ - switch ((val >> 2) & 0x7) { + /* Decode the command protocol. + VIA-specific modes (0x4 and [0x6:0xf]) are undocumented and required real hardware research. */ + cmd = (val >> 2) & 0xf; + smbus_piix4_log("SMBus PIIX4: protocol=%X cmd=%02X data0=%02X data1=%02X\n", cmd, dev->cmd, dev->data0, dev->data1); + switch (cmd) { case 0x0: /* quick R/W */ break; case 0x1: /* byte R/W */ - if (smbus_read) + if (read) /* byte read */ dev->data0 = i2c_read(i2c_smbus, smbus_addr); - else + else /* byte write */ i2c_write(i2c_smbus, smbus_addr, dev->data0); + timer_bytes++; + break; case 0x2: /* byte data R/W */ + /* command write */ i2c_write(i2c_smbus, smbus_addr, dev->cmd); - if (smbus_read) + timer_bytes++; + + if (read) /* byte read */ dev->data0 = i2c_read(i2c_smbus, smbus_addr); - else + else /* byte write */ i2c_write(i2c_smbus, smbus_addr, dev->data0); + timer_bytes++; + break; case 0x3: /* word data R/W */ + /* command write */ i2c_write(i2c_smbus, smbus_addr, dev->cmd); - if (smbus_read) { + timer_bytes++; + + if (read) { /* word read */ dev->data0 = i2c_read(i2c_smbus, smbus_addr); dev->data1 = i2c_read(i2c_smbus, smbus_addr); - } else { + } else { /* word write */ i2c_write(i2c_smbus, smbus_addr, dev->data0); i2c_write(i2c_smbus, smbus_addr, dev->data1); } + timer_bytes += 2; + + break; + + case 0x4: /* process call */ + if (dev->local != SMBUS_VIA) /* VIA only */ + goto unknown_protocol; + + if (!read) { /* command write (only when writing) */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + timer_bytes++; + } + + /* fall-through */ + + case 0xc: /* I2C process call */ + if (!read) { /* word write (only when writing) */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + i2c_write(i2c_smbus, smbus_addr, dev->data1); + timer_bytes += 2; + } + + /* word read */ + dev->data0 = i2c_read(i2c_smbus, smbus_addr); + dev->data1 = i2c_read(i2c_smbus, smbus_addr); + timer_bytes += 2; + break; case 0x5: /* block R/W */ + timer_bytes++; /* account for the SMBus length byte now */ + + /* fall-through */ + + case 0xd: /* I2C block R/W */ i2c_write(i2c_smbus, smbus_addr, dev->cmd); - /* SMBus block data is preceded by a length */ - if (smbus_read) { - dev->data0 = i2c_read(i2c_smbus, smbus_addr); - for (smbus_read = 0; smbus_read < MIN(SMBUS_PIIX4_BLOCK_DATA_SIZE, dev->data0); smbus_read++) - dev->data[smbus_read] = i2c_read(i2c_smbus, smbus_addr); + timer_bytes++; + + if (read) { + /* block read [data0] (I2C) or [first byte] (SMBus) bytes */ + block_len = (cmd == 0x5) ? i2c_read(i2c_smbus, smbus_addr) : dev->data0; + for (read = 0; read < block_len; read++) + dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); } else { - i2c_write(i2c_smbus, smbus_addr, dev->data0); - for (smbus_read = 0; smbus_read < MIN(SMBUS_PIIX4_BLOCK_DATA_SIZE, dev->data0); smbus_read++) - i2c_write(i2c_smbus, smbus_addr, dev->data[smbus_read]); + block_len = dev->data0; + if (cmd == 0x5) /* send length [data0] as first byte on SMBus */ + i2c_write(i2c_smbus, smbus_addr, block_len); + /* block write [data0] bytes */ + for (read = 0; read < block_len; read++) { + if (!i2c_write(i2c_smbus, smbus_addr, dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK])) + break; + } } + timer_bytes += read; + break; - default: - /* other command protocols have undefined behavior, but raise DEV_ERR to be safe */ - dev->next_stat = 0x4; + case 0x6: /* I2C with 10-bit address */ + if (dev->local != SMBUS_VIA) /* VIA only */ + goto unknown_protocol; + + /* command write */ + i2c_write(i2c_smbus, smbus_addr, dev->cmd); + timer_bytes += 1; + + /* fall-through */ + + case 0xe: /* I2C with 7-bit address */ + if (!read) { /* word write (only when writing) */ + i2c_write(i2c_smbus, smbus_addr, dev->data0); + i2c_write(i2c_smbus, smbus_addr, dev->data1); + timer_bytes += 2; + } + + /* block read [first byte] bytes */ + block_len = dev->data[0]; + for (read = 0; read < block_len; read++) + dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); + timer_bytes += read; + + break; + + case 0xf: /* universal */ + /* block write [data0] bytes */ + for (read = 0; read < dev->data0; read++) { + if (!i2c_write(i2c_smbus, smbus_addr, dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK])) + break; + } + timer_bytes += read; + + /* block read [data1] bytes */ + for (read = 0; read < dev->data1; read++) + dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); + timer_bytes += read; + + break; + + default: /* unknown */ +unknown_protocol: + dev->next_stat = 0x04; /* raise DEV_ERR */ + timer_bytes = 0; break; } - /* stop transaction */ + /* Finish transfer. */ i2c_stop(i2c_smbus, smbus_addr); } break; @@ -214,11 +308,11 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) break; } - /* if a status register update was given, dispatch it after 10us to ensure nothing breaks */ - if (dev->next_stat) { - dev->stat = 0x1; /* raise HOST_BUSY while waiting */ + if (dev->next_stat) { /* schedule dispatch of any pending status register update */ + dev->stat = 0x01; /* raise HOST_BUSY while waiting */ timer_disable(&dev->response_timer); - timer_set_delay_u64(&dev->response_timer, 10 * TIMER_USEC); + /* delay = ((half clock for start + half clock for stop) + (bytes * (8 bits + ack))) * 60us period measured on real VIA 686B */ + timer_set_delay_u64(&dev->response_timer, (1 + (timer_bytes * 9)) * 60 * TIMER_USEC); } } @@ -228,7 +322,7 @@ smbus_piix4_response(void *priv) { smbus_piix4_t *dev = (smbus_piix4_t *) priv; - /* dispatch the status register update */ + /* Dispatch the status register update. */ dev->stat = dev->next_stat; } @@ -253,7 +347,8 @@ smbus_piix4_init(const device_t *info) smbus_piix4_t *dev = (smbus_piix4_t *) malloc(sizeof(smbus_piix4_t)); memset(dev, 0, sizeof(smbus_piix4_t)); - i2c_smbus = dev->i2c = i2c_addbus("smbus_piix4"); + dev->local = info->local; + i2c_smbus = dev->i2c = i2c_addbus((dev->local == SMBUS_VIA) ? "smbus_vt82c686b" : "smbus_piix4"); timer_add(&dev->response_timer, smbus_piix4_response, dev, 0); @@ -277,7 +372,16 @@ smbus_piix4_close(void *priv) const device_t piix4_smbus_device = { "PIIX4-compatible SMBus Host Controller", DEVICE_AT, - 0, + SMBUS_PIIX4, + smbus_piix4_init, smbus_piix4_close, NULL, + { NULL }, NULL, NULL, + NULL +}; + +const device_t via_smbus_device = { + "VIA VT82C686B SMBus Host Controller", + DEVICE_AT, + SMBUS_VIA, smbus_piix4_init, smbus_piix4_close, NULL, { NULL }, NULL, NULL, NULL diff --git a/src/include/86box/i2c.h b/src/include/86box/i2c.h index 8db7efb7d..e2135225c 100644 --- a/src/include/86box/i2c.h +++ b/src/include/86box/i2c.h @@ -25,36 +25,37 @@ extern void *i2c_smbus; /* i2c.c */ extern void *i2c_addbus(char *name); extern void i2c_removebus(void *bus_handle); +extern char *i2c_getbusname(void *bus_handle); extern void i2c_sethandler(void *bus_handle, uint8_t base, int size, - void (*start)(void *bus, uint8_t addr, void *priv), + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv), uint8_t (*read)(void *bus, uint8_t addr, void *priv), uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), void (*stop)(void *bus, uint8_t addr, void *priv), void *priv); extern void i2c_removehandler(void *bus_handle, uint8_t base, int size, - void (*start)(void *bus, uint8_t addr, void *priv), + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv), uint8_t (*read)(void *bus, uint8_t addr, void *priv), uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), void (*stop)(void *bus, uint8_t addr, void *priv), void *priv); extern void i2c_handler(int set, void *bus_handle, uint8_t base, int size, - void (*start)(void *bus, uint8_t addr, void *priv), + uint8_t (*start)(void *bus, uint8_t addr, uint8_t read, void *priv), uint8_t (*read)(void *bus, uint8_t addr, void *priv), uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv), void (*stop)(void *bus, uint8_t addr, void *priv), void *priv); extern uint8_t i2c_has_device(void *bus_handle, uint8_t addr); -extern void i2c_start(void *bus_handle, uint8_t addr); +extern uint8_t i2c_start(void *bus_handle, uint8_t addr, uint8_t read); extern uint8_t i2c_read(void *bus_handle, uint8_t addr); extern uint8_t i2c_write(void *bus_handle, uint8_t addr, uint8_t data); extern void i2c_stop(void *bus_handle, uint8_t addr); /* i2c_eeprom.c */ -extern void *i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint16_t size, uint8_t writable); +extern void *i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint32_t size, uint8_t writable); extern void i2c_eeprom_close(void *dev_handle); /* i2c_gpio.c */ diff --git a/src/include/86box/smbus_piix4.h b/src/include/86box/smbus_piix4.h index aa7188393..3173ead4e 100644 --- a/src/include/86box/smbus_piix4.h +++ b/src/include/86box/smbus_piix4.h @@ -19,15 +19,20 @@ #define SMBUS_PIIX4_BLOCK_DATA_SIZE 32 +#define SMBUS_PIIX4_BLOCK_DATA_MASK (SMBUS_PIIX4_BLOCK_DATA_SIZE - 1) -typedef struct -{ +enum { + SMBUS_PIIX4 = 0, + SMBUS_VIA +}; + +typedef struct { + uint32_t local; uint16_t io_base; uint8_t stat, next_stat, ctl, cmd, addr, data0, data1, - index, - data[SMBUS_PIIX4_BLOCK_DATA_SIZE]; + index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE]; pc_timer_t response_timer; void *i2c; } smbus_piix4_t; @@ -38,6 +43,7 @@ extern void smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t #ifdef EMU_DEVICE_H extern const device_t piix4_smbus_device; +extern const device_t via_smbus_device; #endif From 71c406069df93d602b51e0cc06007008216b1db0 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 22 Nov 2020 00:22:24 -0300 Subject: [PATCH 06/16] Fix EuroPC config save crash --- src/cpu/cpu_table.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 92ceb1bb8..585f85831 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -976,9 +976,9 @@ static const cpu_legacy_table_t cpus_pcjr[] = { }; static const cpu_legacy_table_t cpus_europc[] = { - {"8088", 4772728, 1}, - {"8088", 7159092, 1}, - {"8088", 9545456, 1}, + {"8088_europc", 4772728, 1}, + {"8088_europc", 7159092, 1}, + {"8088_europc", 9545456, 1}, {NULL, 0, 0} }; From 1c3a88d06e56a6dda4625010353be67ed173402d Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 22 Nov 2020 00:53:54 -0300 Subject: [PATCH 07/16] Make SMBus block read/write indexes 16-bit to prevent overflowing --- src/device/smbus_piix4.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index ae41347f6..1b2554e20 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -99,6 +99,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) { smbus_piix4_t *dev = (smbus_piix4_t *) priv; uint8_t smbus_addr, cmd, read, block_len, prev_stat, timer_bytes = 0; + uint16_t i; smbus_piix4_log("SMBus PIIX4: write(%02X, %02X)\n", addr, val); @@ -217,19 +218,19 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) if (read) { /* block read [data0] (I2C) or [first byte] (SMBus) bytes */ block_len = (cmd == 0x5) ? i2c_read(i2c_smbus, smbus_addr) : dev->data0; - for (read = 0; read < block_len; read++) - dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); + for (i = 0; i < block_len; i++) + dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); } else { block_len = dev->data0; if (cmd == 0x5) /* send length [data0] as first byte on SMBus */ i2c_write(i2c_smbus, smbus_addr, block_len); /* block write [data0] bytes */ - for (read = 0; read < block_len; read++) { - if (!i2c_write(i2c_smbus, smbus_addr, dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK])) + for (i = 0; i < block_len; i++) { + if (!i2c_write(i2c_smbus, smbus_addr, dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK])) break; } } - timer_bytes += read; + timer_bytes += i; break; @@ -252,24 +253,24 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) /* block read [first byte] bytes */ block_len = dev->data[0]; - for (read = 0; read < block_len; read++) - dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); - timer_bytes += read; + for (i = 0; i < block_len; i++) + dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); + timer_bytes += i; break; case 0xf: /* universal */ /* block write [data0] bytes */ - for (read = 0; read < dev->data0; read++) { - if (!i2c_write(i2c_smbus, smbus_addr, dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK])) + for (i = 0; i < dev->data0; i++) { + if (!i2c_write(i2c_smbus, smbus_addr, dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK])) break; } - timer_bytes += read; + timer_bytes += i; /* block read [data1] bytes */ - for (read = 0; read < dev->data1; read++) - dev->data[read & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); - timer_bytes += read; + for (i = 0; i < dev->data1; i++) + dev->data[i & SMBUS_PIIX4_BLOCK_DATA_MASK] = i2c_read(i2c_smbus, smbus_addr); + timer_bytes += i; break; From 10212afee56745e04770dc641d74b357c06a2caf Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 23 Nov 2020 14:48:32 -0300 Subject: [PATCH 08/16] Add CPU table override config variable --- src/config.c | 5 +++++ src/cpu/cpu.c | 7 +++++++ src/cpu/cpu.h | 1 + 3 files changed, 13 insertions(+) diff --git a/src/config.c b/src/config.c index bf74de17f..d36e11b26 100644 --- a/src/config.c +++ b/src/config.c @@ -625,6 +625,7 @@ load_machine(void) } } cpu_s = (CPU *) &cpu_f->cpus[cpu]; + cpu_override = config_get_int(cat, "cpu_override", 0); cpu_waitstates = config_get_int(cat, "cpu_waitstates", 0); @@ -1787,6 +1788,10 @@ save_machine(void) config_set_string(cat, "cpu_family", (char *) cpu_f->internal_name); config_set_int(cat, "cpu_speed", cpu_f->cpus[cpu].rspeed); config_set_double(cat, "cpu_multi", cpu_f->cpus[cpu].multi); + if (cpu_override) + config_set_int(cat, "cpu_override", cpu_override); + else + config_delete_var(cat, "cpu_override"); /* Forwards compatibility with the previous CPU model system. */ config_delete_var(cat, "cpu_manufacturer"); diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index d434b4e29..536f52a84 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -152,6 +152,7 @@ uint32_t smbase = 0x30000; cpu_family_t *cpu_f; CPU *cpu_s; +int cpu_override; int cpu_effective; int cpu_multi; double cpu_dmulti; @@ -331,6 +332,9 @@ cpu_get_family(const char *internal_name) uint8_t cpu_is_eligible(const cpu_family_t *cpu_family, int cpu, int machine) { + if (cpu_override > 1) /* full override */ + return 1; + /* Get machine. */ const machine_t *machine_s = &machines[machine]; @@ -344,6 +348,9 @@ cpu_is_eligible(const cpu_family_t *cpu_family, int cpu, int machine) if (!(cpu_family->package & packages)) /* package type */ return 0; + if (cpu_override) /* partial override */ + return 1; + const CPU *cpu_s = &cpu_family->cpus[cpu]; if (machine_s->cpu_block & cpu_s->cpu_type) /* CPU type blocklist */ diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index bb89d53ca..73f9524ad 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -375,6 +375,7 @@ extern const cpu_family_t cpu_families[]; extern const cpu_legacy_machine_t cpu_legacy_table[]; extern cpu_family_t *cpu_f; extern CPU *cpu_s; +extern int cpu_override; extern int cpu_isintel; extern int cpu_iscyrix; From 53c1d684fb91be4f3497831c0cb027177f03b241 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 23 Nov 2020 14:48:48 -0300 Subject: [PATCH 09/16] Fix Voodoo ordering --- src/video/vid_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_table.c b/src/video/vid_table.c index a1c7af27d..611be2524 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -149,9 +149,9 @@ video_cards[] = { { "virge375_vbe20_pci", &s3_virge_375_4_pci_device }, { "cl_gd5446_stb_pci", &gd5446_stb_pci_device }, { "tgui9440_pci", &tgui9440_pci_device }, + { "voodoo_banshee_pci", &voodoo_banshee_device }, { "voodoo3_2k_pci", &voodoo_3_2000_device }, { "voodoo3_3k_pci", &voodoo_3_3000_device }, - { "voodoo_banshee_pci", &voodoo_banshee_device }, { "mach64gx_vlb", &mach64gx_vlb_device }, { "et4000w32p_vlb", &et4000w32p_cardex_vlb_device }, #if defined(DEV_BRANCH) && defined(USE_CL5422) From 1e80ac1d15526ef6e0c2b5ca6665adad5957c973 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 23 Nov 2020 14:49:13 -0300 Subject: [PATCH 10/16] Miscellaneous STPC changes --- src/chipset/ali6117.c | 2 +- src/chipset/stpc.c | 263 +++++++++++++++++++----------------------- 2 files changed, 118 insertions(+), 147 deletions(-) diff --git a/src/chipset/ali6117.c b/src/chipset/ali6117.c index d9d2444df..e5dd880f2 100644 --- a/src/chipset/ali6117.c +++ b/src/chipset/ali6117.c @@ -277,7 +277,7 @@ ali6117_reset(void *priv) dev->regs[0x31] = 0x01; dev->regs[0x34] = 0x04; /* enable internal RTC */ dev->regs[0x35] = 0x20; /* enable internal KBC */ - dev->regs[0x36] = (dev->local & 0x4); /* M6117D ID */ + dev->regs[0x36] = dev->local & 0x4; /* M6117D ID */ } diff --git a/src/chipset/stpc.c b/src/chipset/stpc.c index 3d5ceee0f..4d83a3c8b 100644 --- a/src/chipset/stpc.c +++ b/src/chipset/stpc.c @@ -41,11 +41,10 @@ #include <86box/chipset.h> -#define STPC_NB_CLIENT 0x01 -#define STPC_ISAB_CLIENT 0x02 -#define STPC_ISAB_CONSUMER2 0x04 -#define STPC_IDE_ATLAS 0x08 -#define STPC_USB 0x10 +#define STPC_CONSUMER2 0x104a020b +#define STPC_ATLAS 0x104a0210 +#define STPC_ELITE 0x104a021a +#define STPC_CLIENT 0x100e55cc typedef struct stpc_t @@ -119,7 +118,7 @@ stpc_recalcmapping(stpc_t *dev) shadowbios_write = 0; for (reg = 0; reg <= 3; reg++) { - for (bitpair = 0; bitpair <= (reg == 3 ? 0 : 3); bitpair++) { + for (bitpair = 0; bitpair <= ((reg == 3) ? 0 : 3); bitpair++) { if (reg == 3) { size = 0x10000; base = 0xf0000; @@ -166,7 +165,7 @@ stpc_host_write(uint16_t addr, uint8_t val, void *priv) if (addr == dev->host_base) dev->host_offset = val; - else if (addr == dev->host_base + 4) + else if (addr == (dev->host_base + 4)) dev->host_regs[dev->host_offset] = val; } @@ -179,7 +178,7 @@ stpc_host_read(uint16_t addr, void *priv) if (addr == dev->host_base) ret = dev->host_offset; - else if (addr == dev->host_base + 4) + else if (addr == (dev->host_base + 4)) ret = dev->host_regs[dev->host_offset]; else ret = 0xff; @@ -198,7 +197,7 @@ stpc_localbus_write(uint16_t addr, uint8_t val, void *priv) if (addr == dev->localbus_base) dev->localbus_offset = val; - else if (addr == dev->localbus_base + 4) + else if (addr == (dev->localbus_base + 4)) dev->localbus_regs[addr] = val; } @@ -211,7 +210,7 @@ stpc_localbus_read(uint16_t addr, void *priv) if (addr == dev->localbus_base) ret = dev->localbus_offset; - else if (addr == dev->localbus_base + 4) + else if (addr == (dev->localbus_base + 4)) ret = dev->localbus_regs[dev->localbus_offset]; else ret = 0xff; @@ -329,8 +328,8 @@ stpc_ide_bm_handlers(stpc_t *dev) { uint16_t base = (dev->pci_conf[2][0x20] & 0xf0) | (dev->pci_conf[2][0x21] << 8); - sff_bus_master_handler(dev->bm[0], (dev->pci_conf[2][0x04] & 1), base); - sff_bus_master_handler(dev->bm[1], (dev->pci_conf[2][0x04] & 1), base + 8); + sff_bus_master_handler(dev->bm[0], dev->pci_conf[2][0x04] & 1, base); + sff_bus_master_handler(dev->bm[1], dev->pci_conf[2][0x04] & 1, base + 8); } @@ -352,7 +351,7 @@ stpc_ide_write(int func, int addr, uint8_t val, void *priv) break; case 0x05: - dev->pci_conf[2][addr] = (val & 0x01); + dev->pci_conf[2][addr] = val & 0x01; break; case 0x07: @@ -441,13 +440,13 @@ stpc_ide_read(int func, int addr, void *priv) uint8_t ret; if (func > 0) - ret = 0xff; + ret = 0xff; else { ret = dev->pci_conf[2][addr]; if (addr == 0x48) { ret &= 0xfc; - ret |= (!!(dev->bm[0]->status & 0x04)); - ret |= ((!!(dev->bm[1]->status & 0x04)) << 1); + ret |= !!(dev->bm[0]->status & 0x04); + ret |= (!!(dev->bm[1]->status & 0x04)) << 1; } } @@ -461,9 +460,9 @@ stpc_isab_write(int func, int addr, uint8_t val, void *priv) { stpc_t *dev = (stpc_t *) priv; - if (func == 1 && !(dev->local & STPC_IDE_ATLAS)) { - stpc_ide_write(0, addr, val, priv); - return; + if ((func == 1) && (dev->local != STPC_ATLAS)) { + stpc_ide_write(0, addr, val, priv); + return; } stpc_log("STPC: isab_write(%d, %02X, %02X)\n", func, addr, val); @@ -492,12 +491,12 @@ stpc_isab_read(int func, int addr, void *priv) stpc_t *dev = (stpc_t *) priv; uint8_t ret; - if ((func == 1) && !(dev->local & STPC_IDE_ATLAS)) - ret = stpc_ide_read(0, addr, priv); + if ((func == 1) && (dev->local != STPC_ATLAS)) + ret = stpc_ide_read(0, addr, priv); else if (func > 0) - ret = 0xff; + ret = 0xff; else - ret = dev->pci_conf[1][addr]; + ret = dev->pci_conf[1][addr]; stpc_log("STPC: isab_read(%d, %02X) = %02X\n", func, addr, ret); return ret; @@ -547,9 +546,9 @@ stpc_usb_read(int func, int addr, void *priv) uint8_t ret; if (func > 0) - ret = 0xff; + ret = 0xff; else - ret = dev->pci_conf[3][addr]; + ret = dev->pci_conf[3][addr]; stpc_log("STPC: usb_read(%d, %02X) = %02X\n", func, addr, ret); return ret; @@ -589,34 +588,35 @@ stpc_remap_localbus(stpc_t *dev, uint16_t localbus_base) static uint8_t stpc_serial_handlers(uint8_t val) { - stpc_serial_t *dev; - if (!(dev = device_get_priv(&stpc_serial_device))) { - stpc_log("STPC: Not remapping UARTs, disabled by strap (raw %02X)\n", val); - return 0; + stpc_serial_t *dev = device_get_priv(&stpc_serial_device); + if (!dev) { + stpc_log("STPC: Not remapping UARTs, disabled by strap (raw %02X)\n", val); + return 0; } - uint16_t uart0_io = 0x3f8, uart0_irq = 4, uart1_io = 0x3f8, uart1_irq = 3; + uint16_t uart0_io = 0x3f8, uart1_io = 0x3f8; + uint8_t uart0_irq = 4, uart1_irq = 3; if (val & 0x10) - uart1_io -= 0x100; + uart1_io &= 0xfeff; if (val & 0x20) - uart1_io -= 0x10; + uart1_io &= 0xffef; if (val & 0x40) - uart0_io -= 0x100; + uart0_io &= 0xfeff; if (val & 0x80) - uart0_io -= 0x10; + uart0_io &= 0xffef; if (uart0_io == uart1_io) { - /* Apply defaults if both UARTs are set to the same address. */ - stpc_log("STPC: Both UARTs set to %02X, resetting to defaults\n", uart0_io); - uart0_io = 0x3f8; - uart1_io = 0x2f8; + /* Apply defaults if both UARTs are set to the same address. */ + stpc_log("STPC: Both UARTs set to %02X, resetting to defaults\n", uart0_io); + uart0_io = 0x3f8; + uart1_io = 0x2f8; } - if (uart0_io < 0x300) { - /* The address for UART0 defines the IRQs for both ports. */ - uart0_irq = 3; - uart1_irq = 4; + if (!(uart0_io & 0x100)) { + /* The address for UART0 establishes the IRQs for both ports. */ + uart0_irq = 3; + uart1_irq = 4; } stpc_log("STPC: Remapping UART0 to %04X %d and UART1 to %04X %d (raw %02X)\n", uart0_io, uart0_irq, uart1_io, uart1_irq, val); @@ -714,9 +714,9 @@ stpc_reg_read(uint16_t addr, void *priv) if (addr == 0x22) ret = dev->reg_offset; else if (dev->reg_offset >= 0xc0) - return 0xff; /* Cyrix CPU registers: let the CPU code handle these */ + return 0xff; /* let the CPU code handle Cyrix CPU registers */ else if ((dev->reg_offset == 0x56) || (dev->reg_offset == 0x57)) { - /* ELCR is in here, not in port 4D0h. */ + /* ELCR registers. */ ret = pic_elcr_read(dev->reg_offset, (dev->reg_offset & 1) ? &pic2 : &pic); if (dev->reg_offset == 0x57) ret |= (dev->regs[dev->reg_offset] & 0x01); @@ -738,9 +738,9 @@ stpc_reset(void *priv) memset(dev->regs, 0, sizeof(dev->regs)); dev->regs[0x7b] = 0xff; if (device_get_priv(&stpc_lpt_device)) - dev->regs[0x4c] |= 0x80; /* LPT strap */ + dev->regs[0x4c] |= 0x80; /* LPT strap */ if (stpc_serial_handlers(0x00)) - dev->regs[0x4c] |= 0x03; /* UART straps */ + dev->regs[0x4c] |= 0x03; /* UART straps */ } @@ -754,14 +754,12 @@ stpc_setup(stpc_t *dev) stpc_reg_read, NULL, NULL, stpc_reg_write, NULL, NULL, dev); /* Northbridge */ - if (dev->local & STPC_NB_CLIENT) { - /* Client */ + if (dev->local & STPC_CLIENT) { dev->pci_conf[0][0x00] = 0x0e; dev->pci_conf[0][0x01] = 0x10; dev->pci_conf[0][0x02] = 0x64; dev->pci_conf[0][0x03] = 0x05; } else { - /* Atlas, Elite, Consumer II */ dev->pci_conf[0][0x00] = 0x4a; dev->pci_conf[0][0x01] = 0x10; dev->pci_conf[0][0x02] = 0x0a; @@ -776,31 +774,10 @@ stpc_setup(stpc_t *dev) dev->pci_conf[0][0x0b] = 0x06; /* ISA Bridge */ - if (dev->local & STPC_ISAB_CLIENT) { - /* Client */ - dev->pci_conf[1][0x00] = 0x0e; - dev->pci_conf[1][0x01] = 0x10; - dev->pci_conf[1][0x02] = 0xcc; - dev->pci_conf[1][0x03] = 0x55; - } else if (dev->local & STPC_ISAB_CONSUMER2) { - /* Consumer II */ - dev->pci_conf[1][0x00] = 0x4a; - dev->pci_conf[1][0x01] = 0x10; - dev->pci_conf[1][0x02] = 0x0b; - dev->pci_conf[1][0x03] = 0x02; - } else if (dev->local & STPC_IDE_ATLAS) { - /* Atlas */ - dev->pci_conf[1][0x00] = 0x4a; - dev->pci_conf[1][0x01] = 0x10; - dev->pci_conf[1][0x02] = 0x10; - dev->pci_conf[1][0x03] = 0x02; - } else { - /* Elite */ - dev->pci_conf[1][0x00] = 0x4a; - dev->pci_conf[1][0x01] = 0x10; - dev->pci_conf[1][0x02] = 0x1a; - dev->pci_conf[1][0x03] = 0x02; - } + dev->pci_conf[1][0x00] = dev->local >> 16; + dev->pci_conf[1][0x01] = dev->local >> 24; + dev->pci_conf[1][0x02] = dev->local; + dev->pci_conf[1][0x03] = dev->local >> 8; dev->pci_conf[1][0x04] = 0x0f; @@ -812,24 +789,19 @@ stpc_setup(stpc_t *dev) /* NOTE: This is an erratum in the STPC Atlas programming manual, the programming manuals for the other STPC chipsets say 0x80, which is indeed multi-function (as the STPC Atlas programming manual - indicates as well, and Windows 2000 also issues a 0x7B STOP error if it is 0x40. */ + indicates as well), and Windows 2000 also issues a 0x7B STOP error if it is 0x40. */ dev->pci_conf[1][0x0e] = /*0x40*/ 0x80; /* IDE */ - if (dev->local & STPC_ISAB_CLIENT) { - dev->pci_conf[2][0x00] = 0x0e; - dev->pci_conf[2][0x01] = 0x10; - } else { - dev->pci_conf[2][0x00] = 0x4a; - dev->pci_conf[2][0x01] = 0x10; - } + dev->pci_conf[2][0x00] = dev->local >> 16; + dev->pci_conf[2][0x01] = dev->local >> 24; - if (dev->local & STPC_IDE_ATLAS) { - dev->pci_conf[2][0x02] = 0x28; - dev->pci_conf[2][0x03] = 0x02; + if (dev->local == STPC_ATLAS) { + dev->pci_conf[2][0x02] = 0x28; + dev->pci_conf[2][0x03] = 0x02; } else { - dev->pci_conf[2][0x02] = dev->pci_conf[1][0x02]; - dev->pci_conf[2][0x03] = dev->pci_conf[1][0x03]; + dev->pci_conf[2][0x02] = dev->pci_conf[1][0x02]; + dev->pci_conf[2][0x03] = dev->pci_conf[1][0x03]; } dev->pci_conf[2][0x06] = 0x80; @@ -841,7 +813,7 @@ stpc_setup(stpc_t *dev) /* NOTE: This is an erratum in the STPC Atlas programming manual, the programming manuals for the other STPC chipsets say 0x80, which is indeed multi-function (as the STPC Atlas programming manual - indicates as well, and Windows 2000 also issues a 0x7B STOP error if it is 0x40. */ + indicates as well), and Windows 2000 also issues a 0x7B STOP error if it is 0x40. */ dev->pci_conf[2][0x0e] = /*0x40*/ 0x80; dev->pci_conf[2][0x10] = 0x01; @@ -861,22 +833,22 @@ stpc_setup(stpc_t *dev) /* USB */ if (dev->usb) { - dev->pci_conf[3][0x00] = 0x4a; - dev->pci_conf[3][0x01] = 0x10; - dev->pci_conf[3][0x02] = 0x30; - dev->pci_conf[3][0x03] = 0x02; + dev->pci_conf[3][0x00] = dev->local >> 16; + dev->pci_conf[3][0x01] = dev->local >> 24; + dev->pci_conf[3][0x02] = 0x30; + dev->pci_conf[3][0x03] = 0x02; - dev->pci_conf[3][0x06] = 0x80; - dev->pci_conf[3][0x07] = 0x02; + dev->pci_conf[3][0x06] = 0x80; + dev->pci_conf[3][0x07] = 0x02; - dev->pci_conf[3][0x09] = 0x10; - dev->pci_conf[3][0x0a] = 0x03; - dev->pci_conf[3][0x0b] = 0x0c; + dev->pci_conf[3][0x09] = 0x10; + dev->pci_conf[3][0x0a] = 0x03; + dev->pci_conf[3][0x0b] = 0x0c; /* NOTE: This is an erratum in the STPC Atlas programming manual, the programming manuals for the other STPC chipsets say 0x80, which is indeed multi-function (as the STPC Atlas programming manual - indicates as well, and Windows 2000 also issues a 0x7B STOP error if it is 0x40. */ - dev->pci_conf[3][0x0e] = /*0x40*/ 0x80; + indicates as well), and Windows 2000 also issues a 0x7B STOP error if it is 0x40. */ + dev->pci_conf[3][0x0e] = /*0x40*/ 0x80; } /* PCI setup */ @@ -912,11 +884,10 @@ stpc_init(const device_t *info) pci_add_card(PCI_ADD_NORTHBRIDGE, stpc_nb_read, stpc_nb_write, dev); dev->ide_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, stpc_isab_read, stpc_isab_write, dev); - if (dev->local & STPC_IDE_ATLAS) - dev->ide_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, stpc_ide_read, stpc_ide_write, dev); - if (dev->local & STPC_USB) { - dev->usb = device_add(&usb_device); - pci_add_card(PCI_ADD_SOUTHBRIDGE, stpc_usb_read, stpc_usb_write, dev); + if (dev->local == STPC_ATLAS) { + dev->ide_slot = pci_add_card(PCI_ADD_SOUTHBRIDGE, stpc_ide_read, stpc_ide_write, dev); + dev->usb = device_add(&usb_device); + pci_add_card(PCI_ADD_SOUTHBRIDGE, stpc_usb_read, stpc_usb_write, dev); } dev->bm[0] = device_add_inst(&sff8038i_device, 1); @@ -978,43 +949,43 @@ stpc_lpt_handlers(stpc_lpt_t *dev, uint8_t val) uint8_t old_addr = (dev->reg1 & 0x03), new_addr = (val & 0x03); switch (old_addr) { - case 0x1: - lpt3_remove(); - break; + case 0x1: + lpt3_remove(); + break; - case 0x2: - lpt1_remove(); - break; + case 0x2: + lpt1_remove(); + break; - case 0x3: - lpt2_remove(); - break; + case 0x3: + lpt2_remove(); + break; } switch (new_addr) { - case 0x1: - stpc_log("STPC: Remapping parallel port to LPT3\n"); - lpt3_init(0x3bc); - break; + case 0x1: + stpc_log("STPC: Remapping parallel port to LPT3\n"); + lpt3_init(0x3bc); + break; - case 0x2: - stpc_log("STPC: Remapping parallel port to LPT1\n"); - lpt1_init(0x378); - break; + case 0x2: + stpc_log("STPC: Remapping parallel port to LPT1\n"); + lpt1_init(0x378); + break; - case 0x3: - stpc_log("STPC: Remapping parallel port to LPT2\n"); - lpt2_init(0x278); - break; + case 0x3: + stpc_log("STPC: Remapping parallel port to LPT2\n"); + lpt2_init(0x278); + break; - default: - stpc_log("STPC: Disabling parallel port\n"); - break; + default: + stpc_log("STPC: Disabling parallel port\n"); + break; } dev->reg1 = (val & 0x08); dev->reg1 |= new_addr; - dev->reg1 |= 0x84; /* reserved bits that default to 1 - hardwired? */ + dev->reg1 |= 0x84; /* reserved bits that default to 1; hardwired? */ } @@ -1024,22 +995,22 @@ stpc_lpt_write(uint16_t addr, uint8_t val, void *priv) stpc_lpt_t *dev = (stpc_lpt_t *) priv; if (dev->unlocked < 2) { - /* Cheat a little bit: in reality, any write to any - I/O port is supposed to reset the unlock counter. */ - if ((addr == 0x3f0) && (val == 0x55)) - dev->unlocked++; - else - dev->unlocked = 0; + /* Cheat a little bit: in reality, any write to any + I/O port is supposed to reset the unlock counter. */ + if ((addr == 0x3f0) && (val == 0x55)) + dev->unlocked++; + else + dev->unlocked = 0; } else if (addr == 0x3f0) { - if (val == 0xaa) - dev->unlocked = 0; - else - dev->offset = val; + if (val == 0xaa) + dev->unlocked = 0; + else + dev->offset = val; } else if (dev->offset == 1) { - /* dev->reg1 is set by stpc_lpt_handlers */ - stpc_lpt_handlers(dev, val); + /* dev->reg1 is set by stpc_lpt_handlers */ + stpc_lpt_handlers(dev, val); } else if (dev->offset == 4) { - dev->reg4 = (val & 0x03); + dev->reg4 = (val & 0x03); } } @@ -1092,7 +1063,7 @@ const device_t stpc_client_device = { "STPC Client", DEVICE_PCI, - STPC_NB_CLIENT | STPC_ISAB_CLIENT, + STPC_CLIENT, stpc_init, stpc_close, stpc_reset, @@ -1106,7 +1077,7 @@ const device_t stpc_consumer2_device = { "STPC Consumer-II", DEVICE_PCI, - STPC_ISAB_CONSUMER2, + STPC_CONSUMER2, stpc_init, stpc_close, stpc_reset, @@ -1120,7 +1091,7 @@ const device_t stpc_elite_device = { "STPC Elite", DEVICE_PCI, - 0, + STPC_ELITE, stpc_init, stpc_close, stpc_reset, @@ -1134,7 +1105,7 @@ const device_t stpc_atlas_device = { "STPC Atlas", DEVICE_PCI, - STPC_IDE_ATLAS | STPC_USB, + STPC_ATLAS, stpc_init, stpc_close, stpc_reset, From d6b1d2c63a285667be970a04d30a64c9a88e0c3c Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 23 Nov 2020 14:49:49 -0300 Subject: [PATCH 11/16] I2C overhaul part 5: late, but there's still stuff to do --- src/acpi.c | 4 +- src/device/hwm_lm75.c | 6 +- src/device/i2c_gpio.c | 20 ++-- src/device/serial.c | 61 +++++++++++ src/device/smbus_piix4.c | 6 +- src/include/86box/spd.h | 2 +- src/mem/spd.c | 216 +++++++++++++++++++------------------ src/scsi/scsi_ncr53c8xx.c | 21 ++-- src/video/vid_ati_mach64.c | 6 +- src/video/vid_mga.c | 22 ++++ src/video/vid_s3_virge.c | 8 +- 11 files changed, 227 insertions(+), 145 deletions(-) diff --git a/src/acpi.c b/src/acpi.c index cb1f4d91f..350021e00 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -652,10 +652,8 @@ acpi_reg_write_via_common(int size, uint16_t addr, uint8_t val, void *p) static void acpi_i2c_set(acpi_t *dev) { - if (dev->i2c) { - /* Check direction as well to account for the I2C pull-ups. */ + if (dev->i2c) i2c_gpio_set(dev->i2c, !(dev->regs.gpio_dir & 0x02) || (dev->regs.gpio_val & 0x02), !(dev->regs.gpio_dir & 0x04) || (dev->regs.gpio_val & 0x04)); - } } diff --git a/src/device/hwm_lm75.c b/src/device/hwm_lm75.c index fdb9149ae..19aefe314 100644 --- a/src/device/hwm_lm75.c +++ b/src/device/hwm_lm75.c @@ -152,9 +152,9 @@ lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv) return 0; } else if (dev->i2c_state == 0) { dev->i2c_state = 1; - /* Linux lm75.c driver relies on a 3-bit address register that doesn't change if bit 2 is set. */ - if ((dev->as99127f_i2c_addr >= 0x80) && !(data & 0x04)) - dev->addr_register = (data & 0x7); + /* Linux lm75.c driver relies on the address register not changing if bit 2 is set. */ + if ((dev->as99127f_i2c_addr < 0x80) || !(data & 0x04)) + dev->addr_register = data; return 1; } diff --git a/src/device/i2c_gpio.c b/src/device/i2c_gpio.c index bca2e4a1e..e5ea78121 100644 --- a/src/device/i2c_gpio.c +++ b/src/device/i2c_gpio.c @@ -39,7 +39,7 @@ enum { I2C_TRANSMIT_START, I2C_TRANSMIT, I2C_ACKNOWLEDGE, - I2C_NEGACKNOWLEDGE, + I2C_NOTACKNOWLEDGE, I2C_TRANSACKNOWLEDGE, I2C_TRANSMIT_WAIT }; @@ -131,15 +131,13 @@ i2c_gpio_write(i2c_gpio_t *dev) i2c_gpio_log(1, "I2C GPIO %s: Initiating %s address %02X\n", dev->bus_name, dev->slave_read ? "read from" : "write to", dev->slave_addr); - if (!i2c_has_device(dev->i2c, dev->slave_addr)) { + if (!i2c_has_device(dev->i2c, dev->slave_addr) || + ((i == 0xff) && !i2c_start(dev->i2c, dev->slave_addr, dev->slave_read))) { /* start only once per transfer */ dev->slave_state = SLAVE_INVALID; dev->slave_addr = 0xff; - return I2C_NEGACKNOWLEDGE; + return I2C_NOTACKNOWLEDGE; } - if (i == 0xff) /* start only once per transfer */ - i2c_start(dev->i2c, dev->slave_addr, dev->slave_read); - if (dev->slave_read) { dev->slave_state = SLAVE_SENDDATA; dev->transmit = TRANSMITTER_SLAVE; @@ -154,17 +152,17 @@ i2c_gpio_write(i2c_gpio_t *dev) i2c_gpio_log(1, "I2C GPIO %s: Receiving address %02X\n", dev->bus_name, dev->byte); dev->slave_state = dev->slave_read ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA; if (!i2c_write(dev->i2c, dev->slave_addr, dev->byte)) - return I2C_NEGACKNOWLEDGE; + return I2C_NOTACKNOWLEDGE; break; case SLAVE_RECEIVEDATA: i2c_gpio_log(1, "I2C GPIO %s: Receiving data %02X\n", dev->bus_name, dev->byte); if (!i2c_write(dev->i2c, dev->slave_addr, dev->byte)) - return I2C_NEGACKNOWLEDGE; + return I2C_NOTACKNOWLEDGE; break; case SLAVE_INVALID: - return I2C_NEGACKNOWLEDGE; + return I2C_NOTACKNOWLEDGE; } return I2C_ACKNOWLEDGE; @@ -236,9 +234,9 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) } break; - case I2C_NEGACKNOWLEDGE: + case I2C_NOTACKNOWLEDGE: if (!dev->scl && scl) { - i2c_gpio_log(2, "I2C GPIO %s: Nacking transfer\n", dev->bus_name); + i2c_gpio_log(2, "I2C GPIO %s: Not acknowledging transfer\n", dev->bus_name); sda = 1; dev->pos = 0; dev->state = I2C_IDLE; diff --git a/src/device/serial.c b/src/device/serial.c index b331d4d99..06fd0cfb9 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -186,6 +186,47 @@ write_fifo(serial_t *dev, uint8_t dat) } +#include +#include <86box/pit.h> +HANDLE serialdbg = NULL; +OVERLAPPED serialdbgoverlapped_r; +OVERLAPPED serialdbgoverlapped_w; +uint8_t serialdbg_reading = 0; +DWORD serialdbg_read; +uint8_t serialdbg_buf[1]; +pc_timer_t serialdbgtimer; +void +serial_dbg_timer(void *p) +{ + double dbps = (double) 115200; + double temp = 0.0; + int word_len = 32; + temp = (double) word_len; + temp = (1000000.0 / dbps) * temp; + if (serialdbg_reading) { + if (HasOverlappedIoCompleted(&serialdbgoverlapped_r)) { + if (!GetOverlappedResult(serialdbg, &serialdbgoverlapped_r, &serialdbg_read, FALSE)) { + return; + } + //pclog("overlapped %d\n", serialdbg_read); + for (uint32_t i = 0; i < serialdbg_read; i++) { + pclog("reading %02X\n", serialdbg_buf[i]); + serial_write_fifo((serial_t *) p, serialdbg_buf[i]); + } + serialdbg_reading = 0; + }// else pclog(" not yet\n"); + } else { + if (!ReadFile(serialdbg, serialdbg_buf, sizeof(serialdbg_buf), &serialdbg_read, &serialdbgoverlapped_r) && GetLastError() != ERROR_IO_PENDING) { + pclog("serial broken (read) %08X\n", GetLastError()); + CancelIo(serialdbg); + return; + } + serialdbg_reading = 1; + } + timer_on_auto(&serialdbgtimer, temp);//((serial_t *) p)->transmit_period); +} + + void serial_write_fifo(serial_t *dev, uint8_t dat) { @@ -193,6 +234,8 @@ serial_write_fifo(serial_t *dev, uint8_t dat) if (!(dev->mctrl & 0x10)) write_fifo(dev, dat); + else + pclog("fifo not in rx mode?\n"); } @@ -203,6 +246,14 @@ serial_transmit(serial_t *dev, uint8_t val) write_fifo(dev, val); else if (dev->sd->dev_write) dev->sd->dev_write(dev, dev->sd->priv, val); + if (serialdbg && dev->base_address == SERIAL1_ADDR) { + uint8_t buf[1]; + buf[0] = val; + pclog("writing %02X...", buf[0]); + WriteFile(serialdbg, buf, 1, NULL, &serialdbgoverlapped_w); + //while (!HasOverlappedIoCompleted(&serialdbgoverlapped_w)); + pclog("written\n"); + } } @@ -323,6 +374,7 @@ serial_update_speed(serial_t *dev) if (timer_is_enabled(&dev->timeout_timer)) timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); + //pclog("SPEED UPDATED!!! %f\n", dev->transmit_period); } @@ -704,6 +756,15 @@ serial_init(const device_t *info) next_inst++; + if (dev->base_address == SERIAL1_ADDR) { + serialdbg = CreateFileA(TEXT("\\\\.\\COM4"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + pclog("%02X\n", GetLastError()); + if (serialdbg) + timer_add(&serialdbgtimer, serial_dbg_timer, dev, 1); + else + pclog("serial open failed??\n"); + } + return dev; } diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index 1b2554e20..8d457719f 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -98,8 +98,8 @@ static void smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) { smbus_piix4_t *dev = (smbus_piix4_t *) priv; - uint8_t smbus_addr, cmd, read, block_len, prev_stat, timer_bytes = 0; - uint16_t i; + uint8_t smbus_addr, cmd, read, block_len, prev_stat; + uint16_t timer_bytes = 0, i; smbus_piix4_log("SMBus PIIX4: write(%02X, %02X)\n", addr, val); @@ -207,7 +207,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv) break; case 0x5: /* block R/W */ - timer_bytes++; /* account for the SMBus length byte now */ + timer_bytes++; /* count the SMBus length byte now */ /* fall-through */ diff --git a/src/include/86box/spd.h b/src/include/86box/spd.h index 848210922..3b716028f 100644 --- a/src/include/86box/spd.h +++ b/src/include/86box/spd.h @@ -48,12 +48,12 @@ typedef struct { - const device_t *info; uint8_t slot; uint16_t size; uint16_t row1; uint16_t row2; + uint8_t data[SPD_DATA_SIZE]; void *eeprom; } spd_t; diff --git a/src/mem/spd.c b/src/mem/spd.c index 6ace702c1..36aa5f34f 100644 --- a/src/mem/spd.c +++ b/src/mem/spd.c @@ -33,8 +33,9 @@ int spd_present = 0; -spd_t *spd_devices[SPD_MAX_SLOTS]; -uint8_t spd_data[SPD_MAX_SLOTS][SPD_DATA_SIZE]; +spd_t *spd_modules[SPD_MAX_SLOTS]; + +static const device_t spd_device; #ifdef ENABLE_SPD_LOG @@ -60,30 +61,30 @@ spd_log(const char *fmt, ...) static void spd_close(void *priv) { - spd_t *dev = (spd_t *) priv; + spd_log("SPD: close()\n"); - spd_log("SPD: closing slot %d (SMBus %02X)\n", dev->slot, SPD_BASE_ADDR + dev->slot); - - i2c_eeprom_close(dev->eeprom); + for (uint8_t i = 0; i < SPD_MAX_SLOTS; i++) { + if (spd_modules[i]) + i2c_eeprom_close(spd_modules[i]->eeprom); + } spd_present = 0; - - free(dev); } static void * spd_init(const device_t *info) { - spd_t *dev = spd_devices[info->local]; + spd_log("SPD: init()\n"); - spd_log("SPD: initializing slot %d (SMBus %02X)\n", dev->slot, SPD_BASE_ADDR + dev->slot); - - dev->eeprom = i2c_eeprom_init(i2c_smbus, SPD_BASE_ADDR + dev->slot, spd_data[info->local], SPD_DATA_SIZE, 0); + for (uint8_t i = 0; i < SPD_MAX_SLOTS; i++) { + if (spd_modules[i]) + spd_modules[i]->eeprom = i2c_eeprom_init(i2c_smbus, SPD_BASE_ADDR + i, spd_modules[i]->data, sizeof(spd_modules[i]->data), 0); + } spd_present = 1; - return dev; + return &spd_modules; } @@ -107,71 +108,71 @@ comp_ui16_rev(const void *elem1, const void *elem2) void -spd_populate(uint16_t *vslots, uint8_t slot_count, uint16_t total_size, uint16_t min_module_size, uint16_t max_module_size, uint8_t enable_asym) +spd_populate(uint16_t *rows, uint8_t slot_count, uint16_t total_size, uint16_t min_module_size, uint16_t max_module_size, uint8_t enable_asym) { - uint8_t vslot, next_empty_vslot, split, i; + uint8_t row, next_empty_row, split, i; uint16_t asym; - /* populate vslots with modules in power-of-2 capacities */ - memset(vslots, 0x00, SPD_MAX_SLOTS << 1); - for (vslot = 0; vslot < slot_count && total_size; vslot++) { + /* Populate rows with modules in power-of-2 capacities. */ + memset(rows, 0, SPD_MAX_SLOTS << 1); + for (row = 0; row < slot_count && total_size; row++) { /* populate slot */ - vslots[vslot] = 1 << log2_ui16(MIN(total_size, max_module_size)); - if (total_size >= vslots[vslot]) { - spd_log("SPD: initial vslot %d = %d MB\n", vslot, vslots[vslot]); - total_size -= vslots[vslot]; + rows[row] = 1 << log2_ui16(MIN(total_size, max_module_size)); + if (total_size >= rows[row]) { + spd_log("SPD: Initial row %d = %d MB\n", row, rows[row]); + total_size -= rows[row]; } else { - vslots[vslot] = 0; + rows[row] = 0; break; } } - /* did we populate all the RAM? */ + /* Did we populate all the RAM? */ if (total_size) { - /* work backwards to add the missing RAM as asymmetric modules if possible */ + /* Work backwards to add the missing RAM as asymmetric modules if possible. */ if (enable_asym) { - vslot = slot_count - 1; + row = slot_count - 1; do { - asym = (1 << log2_ui16(MIN(total_size, vslots[vslot]))); - if (vslots[vslot] + asym <= max_module_size) { - vslots[vslot] += asym; + asym = (1 << log2_ui16(MIN(total_size, rows[row]))); + if (rows[row] + asym <= max_module_size) { + rows[row] += asym; total_size -= asym; } - } while ((vslot-- > 0) && total_size); + } while ((row-- > 0) && total_size); } if (total_size) /* still not enough */ - spd_log("SPD: not enough RAM slots (%d) to cover memory (%d MB short)\n", slot_count, total_size); + spd_log("SPD: Not enough RAM slots (%d) to cover memory (%d MB short)\n", slot_count, total_size); } - /* populate empty vslots by splitting modules... */ - split = (total_size == 0); /* ...if possible */ + /* Populate empty rows by splitting modules... */ + split = (total_size == 0); /* ...if possible. */ while (split) { - /* look for a module to split */ + /* Look for a module to split. */ split = 0; - for (vslot = 0; vslot < slot_count; vslot++) { - if ((vslots[vslot] < (min_module_size << 1)) || (vslots[vslot] != (1 << log2_ui16(vslots[vslot])))) + for (row = 0; row < slot_count; row++) { + if ((rows[row] < (min_module_size << 1)) || (rows[row] != (1 << log2_ui16(rows[row])))) continue; /* no module here, module is too small to be split, or asymmetric module */ - /* find next empty vslot */ - next_empty_vslot = 0; - for (i = vslot + 1; i < slot_count && !next_empty_vslot; i++) { - if (!vslots[i]) - next_empty_vslot = i; + /* Find next empty row. */ + next_empty_row = 0; + for (i = row + 1; i < slot_count && !next_empty_row; i++) { + if (!rows[i]) + next_empty_row = i; } - if (!next_empty_vslot) - break; /* no empty vslots left */ + if (!next_empty_row) + break; /* no empty rows left */ - /* split the module into its own vslot and the next empty vslot */ - spd_log("SPD: splitting vslot %d (%d MB) into %d and %d (%d MB each)\n", vslot, vslots[vslot], vslot, next_empty_vslot, vslots[vslot] >> 1); - vslots[vslot] = vslots[next_empty_vslot] = vslots[vslot] >> 1; + /* Split the module into its own row and the next empty row. */ + spd_log("SPD: splitting row %d (%d MB) into %d and %d (%d MB each)\n", row, rows[row], row, next_empty_row, rows[row] >> 1); + rows[row] = rows[next_empty_row] = rows[row] >> 1; split = 1; break; } - /* sort vslots by descending capacity if any were split */ + /* Sort rows by descending capacity if any were split. */ if (split) - qsort(vslots, slot_count, sizeof(uint16_t), comp_ui16_rev); + qsort(rows, slot_count, sizeof(uint16_t), comp_ui16_rev); } } @@ -179,13 +180,12 @@ spd_populate(uint16_t *vslots, uint8_t slot_count, uint16_t total_size, uint16_t void spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) { - uint8_t slot, slot_count, vslot, i; - uint16_t min_module_size, vslots[SPD_MAX_SLOTS], asym; - device_t *info; + uint8_t slot, slot_count, row, i; + uint16_t min_module_size, rows[SPD_MAX_SLOTS], asym; spd_edo_t *edo_data; spd_sdram_t *sdram_data; - /* determine the minimum module size for this RAM type */ + /* Determine the minimum module size for this RAM type. */ switch (ram_type) { case SPD_TYPE_FPM: case SPD_TYPE_EDO: @@ -201,51 +201,42 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) return; } - /* count how many (real) slots are enabled */ + /* Count how many slots are enabled. */ slot_count = 0; for (slot = 0; slot < SPD_MAX_SLOTS; slot++) { - vslots[slot] = 0; - if (slot_mask & (1 << slot)) { + rows[slot] = 0; + if (slot_mask & (1 << slot)) slot_count++; - } } - /* populate vslots */ - spd_populate(vslots, slot_count, (mem_size >> 10), min_module_size, max_module_size, 1); + /* Populate rows. */ + spd_populate(rows, slot_count, (mem_size >> 10), min_module_size, max_module_size, 1); - /* register SPD devices and populate their data according to the vslots */ - vslot = 0; - for (slot = 0; slot < SPD_MAX_SLOTS && vslots[vslot]; slot++) { + /* Register SPD devices and populate their data according to the rows. */ + row = 0; + for (slot = 0; slot < SPD_MAX_SLOTS && rows[row]; slot++) { if (!(slot_mask & (1 << slot))) continue; /* slot disabled */ - info = (device_t *) malloc(sizeof(device_t)); - memset(info, 0, sizeof(device_t)); - info->name = "Serial Presence Detect ROM"; - info->local = slot; - info->init = spd_init; - info->close = spd_close; + spd_modules[slot] = (spd_t *) malloc(sizeof(spd_t)); + memset(spd_modules[slot], 0, sizeof(spd_t)); + spd_modules[slot]->slot = slot; + spd_modules[slot]->size = rows[row]; - spd_devices[slot] = (spd_t *) malloc(sizeof(spd_t)); - memset(spd_devices[slot], 0, sizeof(spd_t)); - spd_devices[slot]->info = info; - spd_devices[slot]->slot = slot; - spd_devices[slot]->size = vslots[vslot]; - - /* determine the second row size, from which the first row size can be obtained */ - asym = vslots[vslot] - (1 << log2_ui16(vslots[vslot])); /* separate the powers of 2 */ + /* Determine the second row size, from which the first row size can be obtained. */ + asym = rows[row] - (1 << log2_ui16(rows[row])); /* separate the powers of 2 */ if (!asym) /* is the module asymmetric? */ - asym = vslots[vslot] >> 1; /* symmetric, therefore divide by 2 */ + asym = rows[row] >> 1; /* symmetric, therefore divide by 2 */ - spd_devices[slot]->row1 = vslots[vslot] - asym; - spd_devices[slot]->row2 = asym; + spd_modules[slot]->row1 = rows[row] - asym; + spd_modules[slot]->row2 = asym; - spd_log("SPD: registering slot %d = vslot %d = %d MB (%d/%d)\n", slot, vslot, vslots[vslot], spd_devices[slot]->row1, spd_devices[slot]->row2); + spd_log("SPD: Registering slot %d = row %d = %d MB (%d/%d)\n", slot, row, rows[row], spd_modules[slot]->row1, spd_modules[slot]->row2); switch (ram_type) { case SPD_TYPE_FPM: case SPD_TYPE_EDO: - edo_data = (spd_edo_t *) &spd_data[slot]; + edo_data = (spd_edo_t *) &spd_modules[slot]->data; memset(edo_data, 0, sizeof(spd_edo_t)); /* EDO SPD is specified by JEDEC and present in some modules, but @@ -254,10 +245,10 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) edo_data->bytes_used = 0x80; edo_data->spd_size = 0x08; edo_data->mem_type = ram_type; - edo_data->row_bits = SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row1)); /* first row */ + edo_data->row_bits = SPD_ROLLUP(7 + log2_ui16(spd_modules[slot]->row1)); /* first row */ edo_data->col_bits = 9; - if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ - edo_data->row_bits |= SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row2)) << 4; /* second row, if different from first */ + if (spd_modules[slot]->row1 != spd_modules[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ + edo_data->row_bits |= SPD_ROLLUP(7 + log2_ui16(spd_modules[slot]->row2)) << 4; /* second row, if different from first */ edo_data->col_bits |= 9 << 4; /* same as first row, but just in case */ } edo_data->banks = 2; @@ -269,7 +260,7 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) edo_data->dram_width = 8; edo_data->spd_rev = 0x12; - sprintf(edo_data->part_no, EMU_NAME "-%s-%03dM", (ram_type == SPD_TYPE_FPM) ? "FPM" : "EDO", vslots[vslot]); + sprintf(edo_data->part_no, EMU_NAME "-%s-%03dM", (ram_type == SPD_TYPE_FPM) ? "FPM" : "EDO", rows[row]); for (i = strlen(edo_data->part_no); i < sizeof(edo_data->part_no); i++) edo_data->part_no[i] = ' '; /* part number should be space-padded */ edo_data->rev_code[0] = BCD8(EMU_VERSION_MAJ); @@ -278,22 +269,22 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) edo_data->mfg_week = 17; for (i = 0; i < 63; i++) - edo_data->checksum += spd_data[slot][i]; + edo_data->checksum += spd_modules[slot]->data[i]; for (i = 0; i < 129; i++) - edo_data->checksum2 += spd_data[slot][i]; + edo_data->checksum2 += spd_modules[slot]->data[i]; break; case SPD_TYPE_SDRAM: - sdram_data = (spd_sdram_t *) &spd_data[slot]; + sdram_data = (spd_sdram_t *) &spd_modules[slot]->data; memset(sdram_data, 0, sizeof(spd_sdram_t)); sdram_data->bytes_used = 0x80; sdram_data->spd_size = 0x08; sdram_data->mem_type = ram_type; - sdram_data->row_bits = SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row1)); /* first row */ + sdram_data->row_bits = SPD_ROLLUP(6 + log2_ui16(spd_modules[slot]->row1)); /* first row */ sdram_data->col_bits = 9; - if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ - sdram_data->row_bits |= SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row2)) << 4; /* second row, if different from first */ + if (spd_modules[slot]->row1 != spd_modules[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */ + sdram_data->row_bits |= SPD_ROLLUP(6 + log2_ui16(spd_modules[slot]->row2)) << 4; /* second row, if different from first */ sdram_data->col_bits |= 9 << 4; /* same as first row, but just in case */ } sdram_data->rows = 2; @@ -313,18 +304,18 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) sdram_data->tclk3 = 0xF0; /* 15 ns = 66.7 MHz */ sdram_data->tac2 = sdram_data->tac3 = 0x10; sdram_data->trp = sdram_data->trrd = sdram_data->trcd = sdram_data->tras = 1; - if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { + if (spd_modules[slot]->row1 != spd_modules[slot]->row2) { /* Utilities interpret bank_density a bit differently on asymmetric modules. */ - sdram_data->bank_density = 1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 2); /* first row */ - sdram_data->bank_density |= 1 << (log2_ui16(spd_devices[slot]->row2 >> 1) - 2); /* second row */ + sdram_data->bank_density = 1 << (log2_ui16(spd_modules[slot]->row1 >> 1) - 2); /* first row */ + sdram_data->bank_density |= 1 << (log2_ui16(spd_modules[slot]->row2 >> 1) - 2); /* second row */ } else { - sdram_data->bank_density = 1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 1); /* symmetric module = only one bit is set */ + sdram_data->bank_density = 1 << (log2_ui16(spd_modules[slot]->row1 >> 1) - 1); /* symmetric module = only one bit is set */ } sdram_data->ca_setup = sdram_data->data_setup = 0x15; sdram_data->ca_hold = sdram_data->data_hold = 0x08; sdram_data->spd_rev = 0x12; - sprintf(sdram_data->part_no, EMU_NAME "-SDR-%03dM", vslots[vslot]); + sprintf(sdram_data->part_no, EMU_NAME "-SDR-%03dM", rows[row]); for (i = strlen(sdram_data->part_no); i < sizeof(sdram_data->part_no); i++) sdram_data->part_no[i] = ' '; /* part number should be space-padded */ sdram_data->rev_code[0] = BCD8(EMU_VERSION_MAJ); @@ -336,15 +327,16 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size) sdram_data->features = 0xFF; for (i = 0; i < 63; i++) - sdram_data->checksum += spd_data[slot][i]; + sdram_data->checksum += spd_modules[slot]->data[i]; for (i = 0; i < 129; i++) - sdram_data->checksum2 += spd_data[slot][i]; + sdram_data->checksum2 += spd_modules[slot]->data[i]; break; } - device_add(info); - vslot++; + row++; } + + device_add(&spd_device); } @@ -352,7 +344,7 @@ void spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit) { uint8_t row, dimm, drb, apollo = 0; - uint16_t size, vslots[SPD_MAX_SLOTS]; + uint16_t size, rows[SPD_MAX_SLOTS]; /* Special case for VIA Apollo Pro family, which jumps from 5F to 56. */ if (reg_max < reg_min) { @@ -363,26 +355,26 @@ spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit /* No SPD: split SIMMs into pairs as if they were "DIMM"s. */ if (!spd_present) { dimm = ((reg_max - reg_min) + 1) >> 1; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */ - spd_populate(vslots, dimm, mem_size >> 10, drb_unit, 1 << (log2_ui16(machines[machine].max_ram / dimm)), 0); + spd_populate(rows, dimm, mem_size >> 10, drb_unit, 1 << (log2_ui16(machines[machine].max_ram / dimm)), 0); } /* Write DRBs for each row. */ - spd_log("Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit); + spd_log("SPD: Writing DRBs... regs=[%02X:%02X] unit=%d\n", reg_min, reg_max, drb_unit); for (row = 0; row <= (reg_max - reg_min); row++) { dimm = (row >> 1); size = 0; if (spd_present) { /* SPD enabled: use SPD info for this slot, if present. */ - if (spd_devices[dimm]) { - if (spd_devices[dimm]->row1 < drb_unit) /* hack within a hack: turn a double-sided DIMM that is too small into a single-sided one */ + if (spd_modules[dimm]) { + if (spd_modules[dimm]->row1 < drb_unit) /* hack within a hack: turn a double-sided DIMM that is too small into a single-sided one */ size = (row & 1) ? 0 : drb_unit; else - size = (row & 1) ? spd_devices[dimm]->row2 : spd_devices[dimm]->row1; + size = (row & 1) ? spd_modules[dimm]->row2 : spd_modules[dimm]->row1; } } else { /* No SPD: use the values calculated above. */ - size = (vslots[dimm] >> 1); + size = (rows[dimm] >> 1); } /* Determine the DRB register to write. */ @@ -399,6 +391,16 @@ spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit regs[drb] = regs[drb - 1]; if (size) regs[drb] += size / drb_unit; /* this will intentionally overflow on 440GX with 2 GB */ - spd_log("DRB[%d] = %d MB (%02Xh raw)\n", row, size, regs[drb]); + spd_log("SPD: DRB[%d] = %d MB (%02Xh raw)\n", row, size, regs[drb]); } } + + +static const device_t spd_device = { + "Serial Presence Detect ROMs", + DEVICE_ISA, + 0, + spd_init, spd_close, NULL, + { NULL }, NULL, NULL, + NULL +}; diff --git a/src/scsi/scsi_ncr53c8xx.c b/src/scsi/scsi_ncr53c8xx.c index 507bf339b..ca0273cc8 100644 --- a/src/scsi/scsi_ncr53c8xx.c +++ b/src/scsi/scsi_ncr53c8xx.c @@ -186,6 +186,7 @@ /* Flag set if this is a tagged command. */ #define NCR_TAG_VALID (1 << 16) +#define NCR_NVRAM_SIZE 2048 #define NCR_BUF_SIZE 4096 typedef struct ncr53c8xx_request { @@ -226,9 +227,9 @@ typedef struct { int msg_action; int msg_len; uint8_t msg[NCR_MAX_MSGIN_LEN]; - uint8_t nvram[2048]; /* 24C16 EEPROM (16 kbit) */ + uint8_t nvram[NCR_NVRAM_SIZE]; /* 24C16 EEPROM (16 Kbit) */ void *i2c, *eeprom; - uint8_t ram[NCR_BUF_SIZE]; /* NCR 53c875 RAM (4 kB). */ + uint8_t ram[NCR_BUF_SIZE]; /* NCR 53C875 RAM (4 KB) */ /* 0 if SCRIPTS are running or stopped. * 1 if a Wait Reselect instruction has been issued. * 2 if processing DMA from ncr53c8xx_execute_script. @@ -2584,15 +2585,15 @@ ncr53c8xx_close(void *priv) ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; if (dev) { - /* Save the serial EEPROM. */ - ncr53c8xx_eeprom(dev, 1); - if (dev->eeprom) i2c_eeprom_close(dev->eeprom); if (dev->i2c) i2c_gpio_close(dev->i2c); + /* Save the serial EEPROM. */ + ncr53c8xx_eeprom(dev, 1); + free(dev); dev = NULL; } @@ -2611,7 +2612,7 @@ static const device_config_t ncr53c8xx_pci_config[] = { const device_t ncr53c810_pci_device = { - "NCR 53c810", + "NCR 53C810", DEVICE_PCI, 0x01, ncr53c8xx_init, ncr53c8xx_close, NULL, @@ -2621,7 +2622,7 @@ const device_t ncr53c810_pci_device = const device_t ncr53c810_onboard_pci_device = { - "NCR 53c810 On-Board", + "NCR 53C810 On-Board", DEVICE_PCI, 0x8001, ncr53c8xx_init, ncr53c8xx_close, NULL, @@ -2631,7 +2632,7 @@ const device_t ncr53c810_onboard_pci_device = const device_t ncr53c825a_pci_device = { - "NCR 53c825A", + "NCR 53C825A", DEVICE_PCI, CHIP_825, ncr53c8xx_init, ncr53c8xx_close, NULL, @@ -2641,7 +2642,7 @@ const device_t ncr53c825a_pci_device = const device_t ncr53c860_pci_device = { - "NCR 53c860", + "NCR 53C860", DEVICE_PCI, CHIP_860, ncr53c8xx_init, ncr53c8xx_close, NULL, @@ -2651,7 +2652,7 @@ const device_t ncr53c860_pci_device = const device_t ncr53c875_pci_device = { - "NCR 53c875", + "NCR 53C875", DEVICE_PCI, CHIP_875, ncr53c8xx_init, ncr53c8xx_close, NULL, diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index a353fd6e6..52e125af2 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -2383,8 +2383,8 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) svga_set_ramdac_type(svga, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); ati68860_set_ramdac_type(mach64->svga.ramdac, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); data = (val & (1 << 4)) ? ((val & (1 << 1)) ? 1 : 0) : 1; - clk = (val & (1 << 5)) ? ((val & (1 << 2)) ? 1 : 0) : 1; - i2c_gpio_set(mach64->i2c, clk, data); + clk = (val & (1 << 5)) ? ((val & (1 << 2)) ? 1 : 0) : 1; + i2c_gpio_set(mach64->i2c, clk, data); break; case 0xd0: case 0xd1: case 0xd2: case 0xd3: @@ -3372,7 +3372,7 @@ static void *mach64_common_init(const device_t *info) mach64->fifo_thread = thread_create(fifo_thread, mach64); mach64->i2c = i2c_gpio_init("ddc_ati_mach64"); - mach64->ddc = ddc_init(i2c_gpio_get_bus(mach64->i2c)); + mach64->ddc = ddc_init(i2c_gpio_get_bus(mach64->i2c)); return mach64; } diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index ef3a0dbe5..108d059f5 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -28,6 +28,8 @@ #include <86box/dma.h> #include <86box/plat.h> #include <86box/video.h> +#include <86box/i2c.h> +#include <86box/vid_ddc.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> @@ -499,6 +501,8 @@ typedef struct mystique_t mutex_t *lock; } dma; + + void *i2c, *ddc; } mystique_t; @@ -1020,6 +1024,17 @@ mystique_read_xreg(mystique_t *mystique, int reg) break; case XREG_XGENIODATA: ret = mystique->xgeniodata; + + if (!(mystique->xgenioctrl & 0x08)) { + ret &= 0xf7; + if (i2c_gpio_get_scl(mystique->i2c)) + ret |= 0x08; + } + if (!(mystique->xgenioctrl & 0x02)) { + ret &= 0xfd; + if (i2c_gpio_get_sda(mystique->i2c)) + ret |= 0x02; + } break; case XREG_XSYSPLLM: @@ -1154,6 +1169,7 @@ mystique_write_xreg(mystique_t *mystique, int reg, uint8_t val) case XREG_XGENIOCTRL: mystique->xgenioctrl = val; + i2c_gpio_set(mystique->i2c, !(mystique->xgenioctrl & 0x08) || (mystique->xgeniodata & 0x08), !(mystique->xgenioctrl & 0x02) || (mystique->xgeniodata & 0x02)); break; case XREG_XGENIODATA: mystique->xgeniodata = val; @@ -5009,6 +5025,9 @@ mystique_init(const device_t *info) mystique->svga.vsync_callback = mystique_vsync_callback; + mystique->i2c = i2c_gpio_init("ddc_mga"); + mystique->ddc = ddc_init(i2c_gpio_get_bus(mystique->i2c)); + return mystique; } @@ -5025,6 +5044,9 @@ mystique_close(void *p) svga_close(&mystique->svga); + ddc_close(mystique->ddc); + i2c_gpio_close(mystique->i2c); + free(mystique); } diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index cc5488a27..3a0d98e73 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -285,7 +285,7 @@ typedef struct virge_t int virge_busy; uint8_t subsys_stat, subsys_cntl, advfunc_cntl; - + uint8_t serialport; void *i2c, *ddc; @@ -901,7 +901,7 @@ s3_virge_mmio_read(uint32_t addr, void *p) ret |= SERIAL_PORT_SCR; if ((virge->serialport & SERIAL_PORT_SDW) && i2c_gpio_get_sda(virge->i2c)) ret |= SERIAL_PORT_SDR; - return ret; + return ret; } return 0xff; } @@ -3848,8 +3848,8 @@ static void *s3_virge_init(const device_t *info) virge->fifo_not_full_event = thread_create_event(); virge->fifo_thread = thread_create(fifo_thread, virge); - virge->i2c = i2c_gpio_init("ddc_s3_virge"); - virge->ddc = ddc_init(i2c_gpio_get_bus(virge->i2c)); + virge->i2c = i2c_gpio_init("ddc_s3_virge"); + virge->ddc = ddc_init(i2c_gpio_get_bus(virge->i2c)); return virge; } From 315e3e8d1130b6a911133d02c656e12479a4a6da Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Tue, 24 Nov 2020 01:56:06 -0300 Subject: [PATCH 12/16] I2C overhaul part 6: making DDC actually work --- src/device/i2c_eeprom.c | 2 +- src/device/i2c_gpio.c | 32 +++--- src/device/serial.c | 61 ----------- src/video/vid_ddc.c | 193 +++++++++++++++++++++++++-------- src/video/vid_voodoo_banshee.c | 19 ++-- 5 files changed, 177 insertions(+), 130 deletions(-) diff --git a/src/device/i2c_eeprom.c b/src/device/i2c_eeprom.c index 02e738c89..a27403de8 100644 --- a/src/device/i2c_eeprom.c +++ b/src/device/i2c_eeprom.c @@ -126,7 +126,7 @@ i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint32_t size, uint8_t w dev->addr_len = (size >= 4096) ? 16 : 8; /* use 16-bit addresses on 24C32 and above */ dev->addr_mask = size - 1; - i2c_sethandler(i2c, dev->addr & ~(dev->addr_mask >> dev->addr_len), (dev->addr_mask >> dev->addr_len) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev); + i2c_sethandler(dev->i2c, dev->addr & ~(dev->addr_mask >> dev->addr_len), (dev->addr_mask >> dev->addr_len) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev); return dev; } diff --git a/src/device/i2c_gpio.c b/src/device/i2c_gpio.c index e5ea78121..08096123d 100644 --- a/src/device/i2c_gpio.c +++ b/src/device/i2c_gpio.c @@ -55,7 +55,7 @@ enum { typedef struct { char *bus_name; void *i2c; - uint8_t scl, sda, state, slave_state, slave_addr, + uint8_t scl, sda, receive_wait_sda, state, slave_state, slave_addr, slave_read, last_sda, pos, transmit, byte; } i2c_gpio_t; @@ -188,11 +188,12 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) { i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle; + i2c_gpio_log(3, "I2C GPIO %s: scl=%d->%d sda=%d->%d last_valid_sda=%d state=%d\n", dev->bus_name, dev->scl, scl, dev->last_sda, sda, dev->sda, dev->state); + switch (dev->state) { case I2C_IDLE: - /* dev->scl check breaks NCR SDMS. */ - if (scl && dev->last_sda && !sda) { /* start bit */ - i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from IDLE)\n", dev->bus_name); + if (scl && dev->last_sda && !sda) { /* start condition; dev->scl check breaks NCR SDMS */ + i2c_gpio_log(2, "I2C GPIO %s: Start condition received (from IDLE)\n", dev->bus_name); dev->state = I2C_RECEIVE; dev->pos = 0; } @@ -201,6 +202,8 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) case I2C_RECEIVE_WAIT: if (!dev->scl && scl) dev->state = I2C_RECEIVE; + else if (!dev->scl && !scl && dev->last_sda && sda) /* workaround for repeated start condition on Windows XP DDC */ + dev->receive_wait_sda = 1; /* fall-through */ case I2C_RECEIVE: @@ -213,12 +216,12 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) if (++dev->pos == 8) dev->state = i2c_gpio_write(dev); } else if (dev->scl && scl) { - if (sda && !dev->last_sda) { /* stop bit */ - i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from RECEIVE)\n", dev->bus_name); + if (sda && !dev->last_sda) { /* stop condition */ + i2c_gpio_log(2, "I2C GPIO %s: Stop condition received (from RECEIVE)\n", dev->bus_name); dev->state = I2C_IDLE; i2c_gpio_stop(dev); - } else if (!sda && dev->last_sda) { /* start bit */ - i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from RECEIVE)\n", dev->bus_name); + } else if (!sda && dev->last_sda) { /* start condition */ + i2c_gpio_log(2, "I2C GPIO %s: Start condition received (from RECEIVE)\n", dev->bus_name); dev->pos = 0; dev->slave_state = SLAVE_IDLE; } @@ -229,6 +232,7 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) if (!dev->scl && scl) { i2c_gpio_log(2, "I2C GPIO %s: Acknowledging transfer to %02X\n", dev->bus_name, dev->slave_addr); sda = 0; + dev->receive_wait_sda = 0; /* ack */ dev->pos = 0; dev->state = (dev->transmit == TRANSMITTER_MASTER) ? I2C_RECEIVE_WAIT : I2C_TRANSMIT; } @@ -261,13 +265,13 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) case I2C_TRANSMIT_WAIT: if (dev->scl && scl) { - if (dev->last_sda && !sda) { /* start bit */ + if (dev->last_sda && !sda) { /* start condition */ i2c_gpio_next_byte(dev); dev->pos = 0; i2c_gpio_log(2, "I2C GPIO %s: Next byte = %02X\n", dev->bus_name, dev->byte); } - if (!dev->last_sda && sda) { /* stop bit */ - i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from TRANSMIT_WAIT)\n", dev->bus_name); + if (!dev->last_sda && sda) { /* stop condition */ + i2c_gpio_log(2, "I2C GPIO %s: Stop condition received (from TRANSMIT_WAIT)\n", dev->bus_name); dev->state = I2C_IDLE; i2c_gpio_stop(dev); } @@ -277,8 +281,8 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda) case I2C_TRANSMIT_START: if (!dev->scl && scl) dev->state = I2C_TRANSMIT; - if (dev->scl && scl && !dev->last_sda && sda) { /* stop bit */ - i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from TRANSMIT_START)\n", dev->bus_name); + if (dev->scl && scl && !dev->last_sda && sda) { /* stop condition */ + i2c_gpio_log(2, "I2C GPIO %s: Stop condition received (from TRANSMIT_START)\n", dev->bus_name); dev->state = I2C_IDLE; i2c_gpio_stop(dev); } @@ -327,7 +331,7 @@ i2c_gpio_get_sda(void *dev_handle) return dev->sda; case I2C_RECEIVE_WAIT: - return 0; /* ack */ + return dev->receive_wait_sda; default: return 1; diff --git a/src/device/serial.c b/src/device/serial.c index 06fd0cfb9..b331d4d99 100644 --- a/src/device/serial.c +++ b/src/device/serial.c @@ -186,47 +186,6 @@ write_fifo(serial_t *dev, uint8_t dat) } -#include -#include <86box/pit.h> -HANDLE serialdbg = NULL; -OVERLAPPED serialdbgoverlapped_r; -OVERLAPPED serialdbgoverlapped_w; -uint8_t serialdbg_reading = 0; -DWORD serialdbg_read; -uint8_t serialdbg_buf[1]; -pc_timer_t serialdbgtimer; -void -serial_dbg_timer(void *p) -{ - double dbps = (double) 115200; - double temp = 0.0; - int word_len = 32; - temp = (double) word_len; - temp = (1000000.0 / dbps) * temp; - if (serialdbg_reading) { - if (HasOverlappedIoCompleted(&serialdbgoverlapped_r)) { - if (!GetOverlappedResult(serialdbg, &serialdbgoverlapped_r, &serialdbg_read, FALSE)) { - return; - } - //pclog("overlapped %d\n", serialdbg_read); - for (uint32_t i = 0; i < serialdbg_read; i++) { - pclog("reading %02X\n", serialdbg_buf[i]); - serial_write_fifo((serial_t *) p, serialdbg_buf[i]); - } - serialdbg_reading = 0; - }// else pclog(" not yet\n"); - } else { - if (!ReadFile(serialdbg, serialdbg_buf, sizeof(serialdbg_buf), &serialdbg_read, &serialdbgoverlapped_r) && GetLastError() != ERROR_IO_PENDING) { - pclog("serial broken (read) %08X\n", GetLastError()); - CancelIo(serialdbg); - return; - } - serialdbg_reading = 1; - } - timer_on_auto(&serialdbgtimer, temp);//((serial_t *) p)->transmit_period); -} - - void serial_write_fifo(serial_t *dev, uint8_t dat) { @@ -234,8 +193,6 @@ serial_write_fifo(serial_t *dev, uint8_t dat) if (!(dev->mctrl & 0x10)) write_fifo(dev, dat); - else - pclog("fifo not in rx mode?\n"); } @@ -246,14 +203,6 @@ serial_transmit(serial_t *dev, uint8_t val) write_fifo(dev, val); else if (dev->sd->dev_write) dev->sd->dev_write(dev, dev->sd->priv, val); - if (serialdbg && dev->base_address == SERIAL1_ADDR) { - uint8_t buf[1]; - buf[0] = val; - pclog("writing %02X...", buf[0]); - WriteFile(serialdbg, buf, 1, NULL, &serialdbgoverlapped_w); - //while (!HasOverlappedIoCompleted(&serialdbgoverlapped_w)); - pclog("written\n"); - } } @@ -374,7 +323,6 @@ serial_update_speed(serial_t *dev) if (timer_is_enabled(&dev->timeout_timer)) timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); - //pclog("SPEED UPDATED!!! %f\n", dev->transmit_period); } @@ -756,15 +704,6 @@ serial_init(const device_t *info) next_inst++; - if (dev->base_address == SERIAL1_ADDR) { - serialdbg = CreateFileA(TEXT("\\\\.\\COM4"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); - pclog("%02X\n", GetLastError()); - if (serialdbg) - timer_add(&serialdbgtimer, serial_dbg_timer, dev, 1); - else - pclog("serial open failed??\n"); - } - return dev; } diff --git a/src/video/vid_ddc.c b/src/video/vid_ddc.c index f84d790e9..fa358486d 100644 --- a/src/video/vid_ddc.c +++ b/src/video/vid_ddc.c @@ -10,10 +10,8 @@ * * * - * Authors: Sarah Walker, - * RichardG, + * Authors: RichardG, * - * Copyright 2008-2020 Sarah Walker. * Copyright 2020 RichardG. */ #include @@ -27,57 +25,160 @@ #include <86box/i2c.h> -static uint8_t edid_data[128] = { - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /* Fixed header pattern */ - 0x09, 0xf8, /* Manufacturer "BOX" - apparently unassigned by UEFI - and it has to be big endian */ - 0x00, 0x00, /* Product code */ - 0x12, 0x34, 0x56, 0x78, /* Serial number */ - 47, 30, /* Manufacturer week and year */ - 0x01, 0x03, /* EDID version (1.3) */ +#define STD_TIMING(idx, width, aspect_ratio) do { \ + edid.std_timings[idx].horiz_pixels = ((width) / 8) - 31; \ + edid.std_timings[idx].aspect_ratio_refresh_rate = (aspect_ratio) << 6; /* 60 Hz */ \ + } while (0) - 0x08, /* Analog input, separate sync */ - 34, 0, /* Landscape, 4:3 */ - 0, /* Gamma */ - 0x08, /* RGB color */ - 0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /* Chromaticity */ - - 0xff, 0xff, 0xff, /* Established timing bitmap */ - 0x00, 0x00, /* Standard timing information */ - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - - /* Detailed mode descriptions */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, /* No extensions */ - 0x00 +enum { + STD_ASPECT_16_10 = 0x0, + STD_ASPECT_4_3, + STD_ASPECT_5_4, + STD_ASPECT_16_9 }; +typedef struct { + uint8_t horiz_pixels, aspect_ratio_refresh_rate; +} edid_std_timing_t; + +typedef struct { + uint8_t pixel_clock_lsb, pixel_clock_msb, h_active_lsb, h_blank_lsb, + h_active_blank_msb, v_active_lsb, v_blank_lsb, v_active_blank_msb, + h_front_porch_lsb, h_sync_pulse_lsb, v_front_porch_sync_pulse_lsb, + hv_front_porch_sync_pulse_msb, h_size_lsb, v_size_lsb, hv_size_msb, + h_border, v_border, features; +} edid_detailed_timing_t; + +typedef struct { + uint8_t min_v_field, max_v_field, min_h_line, max_h_line, max_pixel_clock, + timing_type; + union { + uint8_t padding[7]; + struct { + uint8_t reserved, gtf_start_freq, gtf_c, gtf_m_lsb, gtf_m_msb, + gtf_k, gtf_j; + }; + struct { + uint8_t cvt_version, add_clock_precision, max_active_pixels, + aspect_ratios, aspect_ratio_pref, scaling_support, + refresh_pref; + }; + }; +} edid_range_limits_t; + +typedef struct { + uint8_t version, timings[6], reserved[6]; +} edid_established_timings3_t; + +typedef struct { + uint8_t version; + struct { + uint8_t lines_lsb, lines_msb_aspect_ratio, refresh_rate; + } timings[4]; +} edid_cvt_timings_t; + +typedef struct { + uint8_t magic[2], reserved, type, range_limit_offsets; + union { + char ascii[13]; + edid_range_limits_t range_limits; + edid_established_timings3_t established_timings3; + edid_cvt_timings_t cvt_timings; + }; +} edid_descriptor_t; + +typedef struct { + uint8_t magic[8], mfg[2], mfg_product[2], serial[4], mfg_week, mfg_year, + edid_version, edid_rev; + uint8_t input_params, horiz_size, vert_size, gamma, features; + uint8_t chromaticity[10], established_timings[3]; + edid_std_timing_t std_timings[8]; + union { + edid_detailed_timing_t detailed_timings[4]; + edid_descriptor_t descriptors[4]; + }; + uint8_t extensions, checksum; +} edid_t; + + +static edid_t edid; + void * ddc_init(void *i2c) { - uint8_t checksum = 0; - for (int c = 0; c < 127; c++) - checksum += edid_data[c]; - edid_data[127] = 256 - checksum; + memset(&edid.magic[1], 0xff, sizeof(edid.magic) - 2); + edid.magic[0] = edid.magic[7] = 0x00; - return i2c_eeprom_init(i2c, 0x50, edid_data, sizeof(edid_data), 0); + edid.mfg[0] = 0x09; /* manufacturer "BOX" (apparently unassigned by UEFI) */ + edid.mfg[1] = 0xf8; + edid.mfg_week = 48; + edid.mfg_year = 2020 - 1990; + edid.edid_version = 0x01; + edid.edid_rev = 0x03; /* EDID 1.3 */ + + edid.input_params = 0x0e; /* analog input; separate sync; composite sync; sync on green */ + edid.horiz_size = ((4.0 / 3.0) * 100) - 99; /* landscape 4:3 */ + edid.features = 0x09; /* RGB color; CVT */ + + edid.chromaticity[0] = 0x81; + edid.chromaticity[1] = 0xf1; + edid.chromaticity[2] = 0xa3; + edid.chromaticity[3] = 0x57; + edid.chromaticity[4] = 0x53; + edid.chromaticity[5] = 0x9f; + edid.chromaticity[6] = 0x27; + edid.chromaticity[7] = 0x0a; + edid.chromaticity[8] = 0x50; + edid.chromaticity[9] = 0x00; + + memset(&edid.established_timings, 0xff, sizeof(edid.established_timings)); /* all enabled */ + + memset(&edid.std_timings, 0x01, sizeof(edid.std_timings)); /* pad unused entries with 0x01 */ + STD_TIMING(0, 800, STD_ASPECT_4_3); /* 800x600 (preferred) */ + STD_TIMING(1, 1280, STD_ASPECT_16_9); /* 1280x720 */ + STD_TIMING(1, 1280, STD_ASPECT_16_10); /* 1280x800 */ + STD_TIMING(2, 1366, STD_ASPECT_16_9); /* 1360x768 (closest to 1366x768) */ + STD_TIMING(3, 1600, STD_ASPECT_16_9); /* 1600x900 */ + STD_TIMING(4, 1920, STD_ASPECT_16_9); /* 1920x1080 */ + STD_TIMING(5, 2048, STD_ASPECT_4_3); /* 2048x1536 */ + + /* Detailed timings for the preferred resolution of 800x600 */ + edid.detailed_timings[0].pixel_clock_lsb = 0xa0; /* 40000 KHz */ + edid.detailed_timings[0].pixel_clock_msb = 0x0f; + edid.detailed_timings[0].h_active_lsb = 800 & 0xff; + edid.detailed_timings[0].h_blank_lsb = 256 & 0xff; + edid.detailed_timings[0].h_active_blank_msb = ((800 >> 4) & 0xf0) | ((256 >> 8) & 0x0f); + edid.detailed_timings[0].v_active_lsb = 600 & 0xff; + edid.detailed_timings[0].v_blank_lsb = 28; + edid.detailed_timings[0].v_active_blank_msb = (600 >> 4) & 0xf0; + edid.detailed_timings[0].h_front_porch_lsb = 40; + edid.detailed_timings[0].h_sync_pulse_lsb = 128; + edid.detailed_timings[0].v_front_porch_sync_pulse_lsb = (1 << 4) | 4; + + edid.descriptors[1].type = 0xf7; /* established timings 3 */ + edid.descriptors[1].established_timings3.version = 0x10; + memset(&edid.descriptors[1].established_timings3.timings, 0xff, sizeof(edid.descriptors[1].established_timings3.timings)); /* all enabled */ + + edid.descriptors[2].type = 0xfc; /* display name */ + memcpy(&edid.descriptors[2].ascii, "86Box Monitor", 13); /* exactly 13 characters (would otherwise require LF termination and space padding) */ + + edid.descriptors[3].type = 0xfd; /* range limits */ + edid.descriptors[3].range_limits.min_v_field = 1; + edid.descriptors[3].range_limits.max_v_field = -1; + edid.descriptors[3].range_limits.min_h_line = 1; + edid.descriptors[3].range_limits.max_h_line = -1; + edid.descriptors[3].range_limits.max_pixel_clock = -1; + edid.descriptors[3].range_limits.timing_type = 0x00; /* default GTF */ + edid.descriptors[3].range_limits.padding[0] = 0x0a; + memset(&edid.descriptors[3].range_limits.padding[1], 0x20, sizeof(edid.descriptors[3].range_limits.padding) - 1); + + uint8_t *edid_data = (uint8_t *) &edid; + for (uint8_t c = 0; c < 127; c++) + edid.checksum += edid_data[c]; + edid.checksum = 256 - edid.checksum; + + return i2c_eeprom_init(i2c, 0x50, edid_data, sizeof(edid), 0); } diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index f7d04a790..5b8aec184 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -118,7 +118,7 @@ typedef struct banshee_t int type; - void *i2c, *ddc; + void *i2c, *i2c_ddc, *ddc; } banshee_t; enum @@ -685,7 +685,8 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) case Video_vidSerialParallelPort: banshee->vidSerialParallelPort = val; // banshee_log("vidSerialParallelPort: write %08x %08x %04x(%08x):%08x\n", val, val & (VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W), CS,cs,cpu_state.pc); - i2c_gpio_set(banshee->i2c, !!(val & VIDSERIAL_DDC_DCK_W), !!(val & VIDSERIAL_DDC_DDA_W)); + i2c_gpio_set(banshee->i2c_ddc, !!(val & VIDSERIAL_DDC_DCK_W), !!(val & VIDSERIAL_DDC_DDA_W)); + i2c_gpio_set(banshee->i2c, !!(val & VIDSERIAL_I2C_SCK_W), !!(val & VIDSERIAL_I2C_SDA_W)); break; case Video_vidScreenSize: @@ -918,14 +919,14 @@ static uint32_t banshee_ext_inl(uint16_t addr, void *p) case Video_vidSerialParallelPort: ret = banshee->vidSerialParallelPort & ~(VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R); - if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DCK_W) && i2c_gpio_get_scl(banshee->i2c)) + if (!(banshee->vidSerialParallelPort & VIDSERIAL_DDC_DCK_W) || i2c_gpio_get_scl(banshee->i2c_ddc)) ret |= VIDSERIAL_DDC_DCK_R; - if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DDA_W) && i2c_gpio_get_sda(banshee->i2c)) + if (!(banshee->vidSerialParallelPort & VIDSERIAL_DDC_DDA_W) || i2c_gpio_get_sda(banshee->i2c_ddc)) ret |= VIDSERIAL_DDC_DDA_R; ret = ret & ~(VIDSERIAL_I2C_SCK_R | VIDSERIAL_I2C_SDA_R); - if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SCK_W) + if (!(banshee->vidSerialParallelPort & VIDSERIAL_I2C_SCK_W) || i2c_gpio_get_scl(banshee->i2c)) ret |= VIDSERIAL_I2C_SCK_R; - if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SDA_W) + if (!(banshee->vidSerialParallelPort & VIDSERIAL_I2C_SDA_W) || i2c_gpio_get_sda(banshee->i2c)) ret |= VIDSERIAL_I2C_SDA_R; // banshee_log("vidSerialParallelPort: read %08x %08x %04x(%08x):%08x\n", ret, ret & (VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R), CS,cs,cpu_state.pc); break; @@ -2628,8 +2629,9 @@ static void *banshee_init_common(const device_t *info, wchar_t *fn, int has_sgra banshee->vidSerialParallelPort = VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W; - banshee->i2c = i2c_gpio_init("ddc_voodoo_banshee"); - banshee->ddc = ddc_init(i2c_gpio_get_bus(banshee->i2c)); + banshee->i2c = i2c_gpio_init("i2c_voodoo_banshee"); + banshee->i2c_ddc = i2c_gpio_init("ddc_voodoo_banshee"); + banshee->ddc = ddc_init(i2c_gpio_get_bus(banshee->i2c_ddc)); video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_banshee); @@ -2677,6 +2679,7 @@ static void banshee_close(void *p) voodoo_card_close(banshee->voodoo); svga_close(&banshee->svga); ddc_close(banshee->ddc); + i2c_gpio_close(banshee->i2c_ddc); i2c_gpio_close(banshee->i2c); free(banshee); From 64249d50a33e62bf125c74434a37812c72896da3 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 25 Nov 2020 00:16:42 -0300 Subject: [PATCH 13/16] I2C overhaul part 7: S3 Trio and Cirrus Logic --- src/chipset/via_pipc.c | 5 +- src/device/i2c.c | 2 +- src/include/86box/vid_ddc.h | 2 +- src/video/vid_cl54xx.c | 27 ++++++ src/video/vid_ddc.c | 150 ++++++++++++++++++--------------- src/video/vid_mga.c | 32 +++---- src/video/vid_s3.c | 39 ++++++++- src/video/vid_s3_virge.c | 24 +++++- src/video/vid_voodoo_banshee.c | 8 +- 9 files changed, 194 insertions(+), 95 deletions(-) diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 5ff1d5e3b..b11ac4548 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -423,7 +423,7 @@ pipc_read(int func, int addr, void *priv) ret |= 0x10; } } - else if ((func <= (pm_func + 2)) && !(dev->pci_isa_regs[0x85] & ((func == (pm_func + 1)) ? 0x04 : 0x08))) /* AC97 / MC97 */ + else if ((func <= (pm_func + 2)) && !(dev->pci_isa_regs[0x85] & ((func == (pm_func + 1)) ? 0x04 : 0x08)) && 0) /* AC97 / MC97; temporarily disabled while unimplemented */ ret = dev->ac97_regs[func - pm_func - 1][addr]; pipc_log("PIPC: read(%d, %02X) = %02X\n", func, addr, ret); @@ -805,6 +805,9 @@ pipc_write(int func, int addr, uint8_t val, void *priv) if ((func == (pm_func + 2)) && ((addr == 0x4a) || (addr == 0x4b) || (dev->pci_isa_regs[0x85] & 0x08))) return; + if (1) /* temporarily disabled while unimplemented */ + return; + switch (addr) { default: dev->ac97_regs[func - pm_func - 1][addr] = val; diff --git a/src/device/i2c.c b/src/device/i2c.c index 75ec557ab..c17f3487c 100644 --- a/src/device/i2c.c +++ b/src/device/i2c.c @@ -112,7 +112,7 @@ i2c_getbusname(void *bus_handle) i2c_bus_t *bus = (i2c_bus_t *) bus_handle; if (!bus_handle) - return; + return(NULL); return(bus->name); } diff --git a/src/include/86box/vid_ddc.h b/src/include/86box/vid_ddc.h index aa5ee86ba..223861436 100644 --- a/src/include/86box/vid_ddc.h +++ b/src/include/86box/vid_ddc.h @@ -20,6 +20,6 @@ # define EMU_VID_DDC_H extern void *ddc_init(void *i2c); -extern void ddc_close(void *dev_handle); +extern void ddc_close(void *eeprom); #endif /*EMU_VID_DDC_H*/ diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 6b2fd4aaa..bb808e1dc 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -33,6 +33,8 @@ #include <86box/device.h> #include <86box/timer.h> #include <86box/video.h> +#include <86box/i2c.h> +#include <86box/vid_ddc.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> @@ -208,6 +210,8 @@ typedef struct gd54xx_t uint32_t extpallook[256]; PALETTE extpal; + + void *i2c, *ddc; } gd54xx_t; @@ -355,6 +359,10 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) if (svga->crtc[0x27] < CIRRUS_ID_CLGD5429) gd54xx->unlocked = (svga->seqregs[6] == 0x12); break; + case 0x08: + if (gd54xx->i2c) + i2c_gpio_set(gd54xx->i2c, !!(val & 0x01), !!(val & 0x02)); + break; case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* VCLK stuff */ gd54xx->vclk_n[svga->seqaddr-0x0b] = val; break; @@ -697,6 +705,15 @@ gd54xx_in(uint16_t addr, void *p) case 6: ret = svga->seqregs[6]; break; + case 0x08: + if (gd54xx->i2c) { + ret &= 0x7b; + if (i2c_gpio_get_scl(gd54xx->i2c)) + ret |= 0x04; + if (i2c_gpio_get_sda(gd54xx->i2c)) + ret |= 0x80; + } + break; case 0x0b: case 0x0c: case 0x0d: case 0x0e: ret = gd54xx->vclk_n[svga->seqaddr-0x0b]; break; @@ -3252,6 +3269,11 @@ static void mca_add(gd5428_mca_read, gd5428_mca_write, gd5428_mca_feedb, NULL, gd54xx); } + if (gd54xx_is_5434(svga)) { + gd54xx->i2c = i2c_gpio_init("ddc_cl54xx"); + gd54xx->ddc = ddc_init(i2c_gpio_get_bus(gd54xx->i2c)); + } + return gd54xx; } @@ -3359,6 +3381,11 @@ gd54xx_close(void *p) gd54xx_t *gd54xx = (gd54xx_t *)p; svga_close(&gd54xx->svga); + + if (gd54xx->i2c) { + ddc_close(gd54xx->ddc); + i2c_gpio_close(gd54xx->i2c); + } free(gd54xx); } diff --git a/src/video/vid_ddc.c b/src/video/vid_ddc.c index fa358486d..41a23a9a2 100644 --- a/src/video/vid_ddc.c +++ b/src/video/vid_ddc.c @@ -26,8 +26,8 @@ #define STD_TIMING(idx, width, aspect_ratio) do { \ - edid.std_timings[idx].horiz_pixels = ((width) / 8) - 31; \ - edid.std_timings[idx].aspect_ratio_refresh_rate = (aspect_ratio) << 6; /* 60 Hz */ \ + edid->standard_timings[idx].horiz_pixels = ((width) / 8) - 31; \ + edid->standard_timings[idx].aspect_ratio_refresh_rate = (aspect_ratio) << 6; /* 60 Hz */ \ } while (0) enum { @@ -39,7 +39,7 @@ enum { typedef struct { uint8_t horiz_pixels, aspect_ratio_refresh_rate; -} edid_std_timing_t; +} edid_standard_timing_t; typedef struct { uint8_t pixel_clock_lsb, pixel_clock_msb, h_active_lsb, h_blank_lsb, @@ -78,7 +78,7 @@ typedef struct { } edid_cvt_timings_t; typedef struct { - uint8_t magic[2], reserved, type, range_limit_offsets; + uint8_t magic[2], reserved, tag, range_limit_offsets; union { char ascii[13]; edid_range_limits_t range_limits; @@ -91,99 +91,111 @@ typedef struct { uint8_t magic[8], mfg[2], mfg_product[2], serial[4], mfg_week, mfg_year, edid_version, edid_rev; uint8_t input_params, horiz_size, vert_size, gamma, features; - uint8_t chromaticity[10], established_timings[3]; - edid_std_timing_t std_timings[8]; + uint8_t red_green_lsb, blue_white_lsb, red_x_msb, red_y_msb, green_x_msb, + green_y_msb, blue_x_msb, blue_y_msb, white_x_msb, white_y_msb; + uint8_t established_timings[3]; + edid_standard_timing_t standard_timings[8]; union { edid_detailed_timing_t detailed_timings[4]; edid_descriptor_t descriptors[4]; }; uint8_t extensions, checksum; + + uint8_t ext_tag, ext_rev, ext_dtd_offset, ext_native_dtds; + union { + edid_detailed_timing_t ext_detailed_timings[6]; + edid_descriptor_t ext_descriptors[6]; + }; + uint8_t padding[15], checksum2; } edid_t; -static edid_t edid; - - void * ddc_init(void *i2c) { - memset(&edid.magic[1], 0xff, sizeof(edid.magic) - 2); - edid.magic[0] = edid.magic[7] = 0x00; + edid_t *edid = malloc(sizeof(edid_t)); + memset(edid, 0, sizeof(edid_t)); - edid.mfg[0] = 0x09; /* manufacturer "BOX" (apparently unassigned by UEFI) */ - edid.mfg[1] = 0xf8; - edid.mfg_week = 48; - edid.mfg_year = 2020 - 1990; - edid.edid_version = 0x01; - edid.edid_rev = 0x03; /* EDID 1.3 */ + memset(&edid->magic[1], 0xff, sizeof(edid->magic) - 2); - edid.input_params = 0x0e; /* analog input; separate sync; composite sync; sync on green */ - edid.horiz_size = ((4.0 / 3.0) * 100) - 99; /* landscape 4:3 */ - edid.features = 0x09; /* RGB color; CVT */ + edid->mfg[0] = 0x09; /* manufacturer "BOX" (apparently unassigned by UEFI) */ + edid->mfg[1] = 0xf8; + edid->mfg_week = 48; + edid->mfg_year = 2020 - 1990; + edid->edid_version = 0x01; + edid->edid_rev = 0x04; /* EDID 1.4 */ - edid.chromaticity[0] = 0x81; - edid.chromaticity[1] = 0xf1; - edid.chromaticity[2] = 0xa3; - edid.chromaticity[3] = 0x57; - edid.chromaticity[4] = 0x53; - edid.chromaticity[5] = 0x9f; - edid.chromaticity[6] = 0x27; - edid.chromaticity[7] = 0x0a; - edid.chromaticity[8] = 0x50; - edid.chromaticity[9] = 0x00; + edid->input_params = 0x0e; /* analog input; separate sync; composite sync; sync on green */ + edid->horiz_size = ((4.0 / 3.0) * 100) - 99; /* landscape 4:3 */ + edid->features = 0x09; /* RGB color; GTF/CVT */ - memset(&edid.established_timings, 0xff, sizeof(edid.established_timings)); /* all enabled */ + edid->red_green_lsb = 0x81; + edid->blue_white_lsb = 0xf1; + edid->red_x_msb = 0xa3; + edid->red_y_msb = 0x57; + edid->green_x_msb = 0x53; + edid->green_y_msb = 0x9f; + edid->blue_x_msb = 0x27; + edid->blue_y_msb = 0x0a; + edid->white_x_msb = 0x50; + edid->white_y_msb = 0x00; - memset(&edid.std_timings, 0x01, sizeof(edid.std_timings)); /* pad unused entries with 0x01 */ - STD_TIMING(0, 800, STD_ASPECT_4_3); /* 800x600 (preferred) */ - STD_TIMING(1, 1280, STD_ASPECT_16_9); /* 1280x720 */ + memset(&edid->established_timings, 0xff, sizeof(edid->established_timings)); /* all enabled */ + + memset(&edid->standard_timings, 0x01, sizeof(edid->standard_timings)); /* pad unused entries */ + STD_TIMING(0, 1280, STD_ASPECT_16_9); /* 1280x720 */ STD_TIMING(1, 1280, STD_ASPECT_16_10); /* 1280x800 */ STD_TIMING(2, 1366, STD_ASPECT_16_9); /* 1360x768 (closest to 1366x768) */ - STD_TIMING(3, 1600, STD_ASPECT_16_9); /* 1600x900 */ - STD_TIMING(4, 1920, STD_ASPECT_16_9); /* 1920x1080 */ - STD_TIMING(5, 2048, STD_ASPECT_4_3); /* 2048x1536 */ + STD_TIMING(3, 1440, STD_ASPECT_16_10); /* 1440x900 */ + STD_TIMING(4, 1600, STD_ASPECT_16_9); /* 1600x900 */ + STD_TIMING(5, 1680, STD_ASPECT_16_10); /* 1680x1050 */ + STD_TIMING(6, 1920, STD_ASPECT_16_9); /* 1920x1080 */ + STD_TIMING(7, 2048, STD_ASPECT_4_3); /* 2048x1536 */ - /* Detailed timings for the preferred resolution of 800x600 */ - edid.detailed_timings[0].pixel_clock_lsb = 0xa0; /* 40000 KHz */ - edid.detailed_timings[0].pixel_clock_msb = 0x0f; - edid.detailed_timings[0].h_active_lsb = 800 & 0xff; - edid.detailed_timings[0].h_blank_lsb = 256 & 0xff; - edid.detailed_timings[0].h_active_blank_msb = ((800 >> 4) & 0xf0) | ((256 >> 8) & 0x0f); - edid.detailed_timings[0].v_active_lsb = 600 & 0xff; - edid.detailed_timings[0].v_blank_lsb = 28; - edid.detailed_timings[0].v_active_blank_msb = (600 >> 4) & 0xf0; - edid.detailed_timings[0].h_front_porch_lsb = 40; - edid.detailed_timings[0].h_sync_pulse_lsb = 128; - edid.detailed_timings[0].v_front_porch_sync_pulse_lsb = (1 << 4) | 4; + /* Detailed timings for the preferred mode of 800x600 */ + edid->detailed_timings[0].pixel_clock_lsb = 0xa0; /* 40000 KHz */ + edid->detailed_timings[0].pixel_clock_msb = 0x0f; + edid->detailed_timings[0].h_active_lsb = 800 & 0xff; + edid->detailed_timings[0].h_blank_lsb = 256 & 0xff; + edid->detailed_timings[0].h_active_blank_msb = ((800 >> 4) & 0xf0) | ((256 >> 8) & 0x0f); + edid->detailed_timings[0].v_active_lsb = 600 & 0xff; + edid->detailed_timings[0].v_blank_lsb = 28; + edid->detailed_timings[0].v_active_blank_msb = (600 >> 4) & 0xf0; + edid->detailed_timings[0].h_front_porch_lsb = 40; + edid->detailed_timings[0].h_sync_pulse_lsb = 128; + edid->detailed_timings[0].v_front_porch_sync_pulse_lsb = (1 << 4) | 4; - edid.descriptors[1].type = 0xf7; /* established timings 3 */ - edid.descriptors[1].established_timings3.version = 0x10; - memset(&edid.descriptors[1].established_timings3.timings, 0xff, sizeof(edid.descriptors[1].established_timings3.timings)); /* all enabled */ + edid->descriptors[1].tag = 0xf7; /* established timings 3 */ + edid->descriptors[1].established_timings3.version = 0x0a; + memset(&edid->descriptors[1].established_timings3.timings, 0xff, sizeof(edid->descriptors[1].established_timings3.timings)); /* all enabled */ - edid.descriptors[2].type = 0xfc; /* display name */ - memcpy(&edid.descriptors[2].ascii, "86Box Monitor", 13); /* exactly 13 characters (would otherwise require LF termination and space padding) */ + edid->descriptors[2].tag = 0xfc; /* display name */ + memcpy(&edid->descriptors[2].ascii, "86Box Monitor", 13); /* exactly 13 characters (would otherwise require LF termination and space padding) */ - edid.descriptors[3].type = 0xfd; /* range limits */ - edid.descriptors[3].range_limits.min_v_field = 1; - edid.descriptors[3].range_limits.max_v_field = -1; - edid.descriptors[3].range_limits.min_h_line = 1; - edid.descriptors[3].range_limits.max_h_line = -1; - edid.descriptors[3].range_limits.max_pixel_clock = -1; - edid.descriptors[3].range_limits.timing_type = 0x00; /* default GTF */ - edid.descriptors[3].range_limits.padding[0] = 0x0a; - memset(&edid.descriptors[3].range_limits.padding[1], 0x20, sizeof(edid.descriptors[3].range_limits.padding) - 1); + edid->descriptors[3].tag = 0xfd; /* range limits */ + edid->descriptors[3].range_limits.min_v_field = 1; + edid->descriptors[3].range_limits.max_v_field = -1; + edid->descriptors[3].range_limits.min_h_line = 1; + edid->descriptors[3].range_limits.max_h_line = -1; + edid->descriptors[3].range_limits.max_pixel_clock = -1; + edid->descriptors[3].range_limits.timing_type = 0x00; /* default GTF */ + edid->descriptors[3].range_limits.padding[0] = 0x0a; + memset(&edid->descriptors[3].range_limits.padding[1], 0x20, sizeof(edid->descriptors[3].range_limits.padding) - 1); - uint8_t *edid_data = (uint8_t *) &edid; + uint8_t *edid_bytes = (uint8_t *) edid; for (uint8_t c = 0; c < 127; c++) - edid.checksum += edid_data[c]; - edid.checksum = 256 - edid.checksum; + edid->checksum += edid_bytes[c]; + edid->checksum = 256 - edid->checksum; + for (uint8_t c = 128; c < 255; c++) + edid->checksum2 += edid_bytes[c]; + edid->checksum2 = 256 - edid->checksum2; - return i2c_eeprom_init(i2c, 0x50, edid_data, sizeof(edid), 0); + return i2c_eeprom_init(i2c, 0x50, edid_bytes, sizeof(edid_t), 0); } void -ddc_close(void *dev_handle) +ddc_close(void *eeprom) { - i2c_eeprom_close(dev_handle); + i2c_eeprom_close(eeprom); } diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 108d059f5..136531457 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -502,7 +502,7 @@ typedef struct mystique_t mutex_t *lock; } dma; - void *i2c, *ddc; + void *i2c, *i2c_ddc, *ddc; } mystique_t; @@ -1023,18 +1023,15 @@ mystique_read_xreg(mystique_t *mystique, int reg) ret = mystique->xgenioctrl; break; case XREG_XGENIODATA: - ret = mystique->xgeniodata; - - if (!(mystique->xgenioctrl & 0x08)) { - ret &= 0xf7; - if (i2c_gpio_get_scl(mystique->i2c)) - ret |= 0x08; - } - if (!(mystique->xgenioctrl & 0x02)) { - ret &= 0xfd; - if (i2c_gpio_get_sda(mystique->i2c)) - ret |= 0x02; - } + ret = mystique->xgeniodata & 0xf0; + if (i2c_gpio_get_scl(mystique->i2c_ddc)) + ret |= 0x08; + if (i2c_gpio_get_scl(mystique->i2c)) + ret |= 0x04; + if (i2c_gpio_get_sda(mystique->i2c_ddc)) + ret |= 0x02; + if (i2c_gpio_get_sda(mystique->i2c)) + ret |= 0x01; break; case XREG_XSYSPLLM: @@ -1169,7 +1166,8 @@ mystique_write_xreg(mystique_t *mystique, int reg, uint8_t val) case XREG_XGENIOCTRL: mystique->xgenioctrl = val; - i2c_gpio_set(mystique->i2c, !(mystique->xgenioctrl & 0x08) || (mystique->xgeniodata & 0x08), !(mystique->xgenioctrl & 0x02) || (mystique->xgeniodata & 0x02)); + i2c_gpio_set(mystique->i2c_ddc, !(mystique->xgenioctrl & 0x08) || (mystique->xgeniodata & 0x08), !(mystique->xgenioctrl & 0x02) || (mystique->xgeniodata & 0x02)); + i2c_gpio_set(mystique->i2c, !(mystique->xgenioctrl & 0x04) || (mystique->xgeniodata & 0x04), !(mystique->xgenioctrl & 0x01) || (mystique->xgeniodata & 0x01)); break; case XREG_XGENIODATA: mystique->xgeniodata = val; @@ -5025,8 +5023,9 @@ mystique_init(const device_t *info) mystique->svga.vsync_callback = mystique_vsync_callback; - mystique->i2c = i2c_gpio_init("ddc_mga"); - mystique->ddc = ddc_init(i2c_gpio_get_bus(mystique->i2c)); + mystique->i2c = i2c_gpio_init("i2c_mga"); + mystique->i2c_ddc = i2c_gpio_init("ddc_mga"); + mystique->ddc = ddc_init(i2c_gpio_get_bus(mystique->i2c_ddc)); return mystique; } @@ -5045,6 +5044,7 @@ mystique_close(void *p) svga_close(&mystique->svga); ddc_close(mystique->ddc); + i2c_gpio_close(mystique->i2c_ddc); i2c_gpio_close(mystique->i2c); free(mystique); diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 704d193ae..89295c60a 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -30,6 +30,8 @@ #include <86box/rom.h> #include <86box/plat.h> #include <86box/video.h> +#include <86box/i2c.h> +#include <86box/vid_ddc.h> #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> #include "cpu.h" @@ -266,6 +268,9 @@ typedef struct s3_t int translate; int enable_8514; volatile int busy, force_busy; + + uint8_t serialport; + void *i2c, *ddc; } s3_t; #define INT_VSY (1 << 0) @@ -274,6 +279,11 @@ typedef struct s3_t #define INT_FIFO_EMP (1 << 3) #define INT_MASK 0xf +#define SERIAL_PORT_SCW (1 << 0) +#define SERIAL_PORT_SDW (1 << 1) +#define SERIAL_PORT_SCR (1 << 2) +#define SERIAL_PORT_SDR (1 << 3) + static void s3_updatemapping(s3_t *s3); static void s3_accel_write(uint32_t addr, uint8_t val, void *p); @@ -1051,6 +1061,10 @@ s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) s3->accel.advfunc_cntl = val; s3_updatemapping(s3); break; + case 0xff20: + s3->serialport = val; + i2c_gpio_set(s3->i2c, !!(val & SERIAL_PORT_SCW), !!(val & SERIAL_PORT_SDW)); + break; default: s3_accel_out_fifo(s3, addr & 0xffff, val); break; @@ -1084,7 +1098,10 @@ s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) default: s3_accel_write_fifo(s3, addr, val); s3_accel_write_fifo(s3, addr + 1, val >> 8); - break; + break; + case 0xff20: + s3_accel_write_fifo(s3, addr, val); + break; } } } else { @@ -1233,6 +1250,10 @@ s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) s3_updatemapping(s3); break; + case 0xff20: + s3_accel_write_fifo(s3, addr, val); + break; + default: s3_accel_write_fifo(s3, addr, val); s3_accel_write_fifo(s3, addr + 1, val >> 8); @@ -2900,6 +2921,14 @@ s3_accel_in(uint16_t port, void *p) else if ((s3->accel.cmd & 0x600) == 0x000 && (s3->accel.cmd & 0x100)) s3_accel_start(1, 1, 0xffffffff, 0xff, s3); return temp; + + case 0xff20: case 0xff21: + temp = s3->serialport & ~(SERIAL_PORT_SCR | SERIAL_PORT_SDR); + if ((s3->serialport & SERIAL_PORT_SCW) && i2c_gpio_get_scl(s3->i2c)) + temp |= SERIAL_PORT_SCR; + if ((s3->serialport & SERIAL_PORT_SDW) && i2c_gpio_get_sda(s3->i2c)) + temp |= SERIAL_PORT_SDR; + return temp; } return 0xff; @@ -2976,7 +3005,7 @@ s3_accel_read(uint32_t addr, void *p) case 0x8504: return s3->subsys_stat; case 0x8505: - return s3->subsys_cntl;; + return s3->subsys_cntl; default: return s3_accel_in(addr & 0xffff, p); } @@ -4662,6 +4691,9 @@ static void *s3_init(const device_t *info) return NULL; } + s3->i2c = i2c_gpio_init("ddc_s3"); + s3->ddc = ddc_init(i2c_gpio_get_bus(s3->i2c)); + return s3; } @@ -4755,6 +4787,9 @@ static void s3_close(void *p) thread_destroy_event(s3->wake_fifo_thread); thread_destroy_event(s3->fifo_not_full_event); + ddc_close(s3->ddc); + i2c_gpio_close(s3->i2c); + free(s3); } diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 3a0d98e73..db04f8e8b 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -447,7 +447,11 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) return; if ((svga->crtcreg == 0x36) && (svga->crtc[0x39] != 0xa5)) return; - if (svga->crtcreg >= 0x80) + if ((svga->crtcreg >= 0x80) +#if defined(DEV_BRANCH) && defined(USE_S3TRIO3D2X) + && !((virge->chip == S3_TRIO3D2X) && (svga->crtcreg == 0xaa)) +#endif + ) return; old = svga->crtc[svga->crtcreg]; svga->crtc[svga->crtcreg] = val; @@ -550,6 +554,12 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) default: svga->bpp = 8; break; } break; + +#if defined(DEV_BRANCH) && defined(USE_S3TRIO3D2X) + case 0xaa: + i2c_gpio_set(virge->i2c, !!(val & SERIAL_PORT_SCW), !!(val & SERIAL_PORT_SDW)); + break; +#endif } if (old != val) { @@ -607,6 +617,18 @@ static uint8_t s3_virge_in(uint16_t addr, void *p) case 0x51: ret = (svga->crtc[0x51] & 0xf0) | ((virge->bank >> 2) & 0xc) | ((virge->ma_ext >> 2) & 3); break; case 0x69: ret = virge->ma_ext; break; case 0x6a: ret = virge->bank; break; +#if defined(DEV_BRANCH) && defined(USE_S3TRIO3D2X) + case 0xaa: /* Trio3D DDC */ + if (virge->chip == S3_TRIO3D2X) { + ret = svga->crtc[0xaa] & ~(SERIAL_PORT_SCR | SERIAL_PORT_SDR); + if ((svga->crtc[0xaa] & SERIAL_PORT_SCW) && i2c_gpio_get_scl(virge->i2c)) + ret |= SERIAL_PORT_SCR; + if ((svga->crtc[0xaa] & SERIAL_PORT_SDW) && i2c_gpio_get_sda(virge->i2c)) + ret |= SERIAL_PORT_SDR; + break; + } + /* fall-through */ +#endif default: ret = svga->crtc[svga->crtcreg]; break; } break; diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 5b8aec184..29ffc1a3e 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -2702,7 +2702,7 @@ static void banshee_force_redraw(void *p) const device_t voodoo_banshee_device = { - "Voodoo Banshee PCI (reference)", + "3dfx Voodoo Banshee", DEVICE_PCI, 0, banshee_init, @@ -2716,7 +2716,7 @@ const device_t voodoo_banshee_device = const device_t creative_voodoo_banshee_device = { - "Creative Labs 3D Blaster Banshee PCI", + "Creative 3D Blaster Banshee", DEVICE_PCI, 0, creative_banshee_init, @@ -2730,7 +2730,7 @@ const device_t creative_voodoo_banshee_device = const device_t voodoo_3_2000_device = { - "Voodoo 3 2000 PCI", + "3dfx Voodoo3 2000", DEVICE_PCI, 0, v3_2000_init, @@ -2744,7 +2744,7 @@ const device_t voodoo_3_2000_device = const device_t voodoo_3_3000_device = { - "Voodoo 3 3000 PCI", + "3dfx Voodoo3 3000", DEVICE_PCI, 0, v3_3000_init, From bede32130d8a717909b7729f55938feb93013a4d Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 25 Nov 2020 14:28:26 -0300 Subject: [PATCH 14/16] Final DDC struct cleanups --- src/video/vid_ddc.c | 62 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/src/video/vid_ddc.c b/src/video/vid_ddc.c index 41a23a9a2..1a07e7898 100644 --- a/src/video/vid_ddc.c +++ b/src/video/vid_ddc.c @@ -26,7 +26,7 @@ #define STD_TIMING(idx, width, aspect_ratio) do { \ - edid->standard_timings[idx].horiz_pixels = ((width) / 8) - 31; \ + edid->standard_timings[idx].horiz_pixels = ((width) >> 3) - 31; \ edid->standard_timings[idx].aspect_ratio_refresh_rate = (aspect_ratio) << 6; /* 60 Hz */ \ } while (0) @@ -49,41 +49,39 @@ typedef struct { h_border, v_border, features; } edid_detailed_timing_t; -typedef struct { - uint8_t min_v_field, max_v_field, min_h_line, max_h_line, max_pixel_clock, - timing_type; - union { - uint8_t padding[7]; - struct { - uint8_t reserved, gtf_start_freq, gtf_c, gtf_m_lsb, gtf_m_msb, - gtf_k, gtf_j; - }; - struct { - uint8_t cvt_version, add_clock_precision, max_active_pixels, - aspect_ratios, aspect_ratio_pref, scaling_support, - refresh_pref; - }; - }; -} edid_range_limits_t; - -typedef struct { - uint8_t version, timings[6], reserved[6]; -} edid_established_timings3_t; - -typedef struct { - uint8_t version; - struct { - uint8_t lines_lsb, lines_msb_aspect_ratio, refresh_rate; - } timings[4]; -} edid_cvt_timings_t; - typedef struct { uint8_t magic[2], reserved, tag, range_limit_offsets; union { char ascii[13]; - edid_range_limits_t range_limits; - edid_established_timings3_t established_timings3; - edid_cvt_timings_t cvt_timings; + struct { + uint8_t min_v_field, max_v_field, min_h_line, max_h_line, max_pixel_clock, + timing_type; + union { + uint8_t padding[7]; + struct { + uint8_t reserved, gtf_start_freq, gtf_c, gtf_m_lsb, gtf_m_msb, + gtf_k, gtf_j; + }; + struct { + uint8_t cvt_version, add_clock_precision, max_active_pixels, + aspect_ratios, aspect_ratio_pref, scaling_support, + refresh_pref; + }; + }; + } range_limits; + struct { + edid_standard_timing_t standard_timings[6]; + uint8_t padding; + } ext_standard_timings; + struct { + uint8_t version; + struct { + uint8_t lines_lsb, lines_msb_aspect_ratio, refresh_rate; + } timings[4]; + } cvt_timings; + struct { + uint8_t version, timings[6], reserved[6]; + } established_timings3; }; } edid_descriptor_t; From 157997fa9b93c591cdbf75e5fc69bdc57ea59d98 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 25 Nov 2020 17:04:35 -0300 Subject: [PATCH 15/16] Cosmetic change to DDC pixel clock value --- src/video/vid_ddc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video/vid_ddc.c b/src/video/vid_ddc.c index 1a07e7898..880adc79e 100644 --- a/src/video/vid_ddc.c +++ b/src/video/vid_ddc.c @@ -151,8 +151,8 @@ ddc_init(void *i2c) STD_TIMING(7, 2048, STD_ASPECT_4_3); /* 2048x1536 */ /* Detailed timings for the preferred mode of 800x600 */ - edid->detailed_timings[0].pixel_clock_lsb = 0xa0; /* 40000 KHz */ - edid->detailed_timings[0].pixel_clock_msb = 0x0f; + edid->detailed_timings[0].pixel_clock_lsb = 4000 & 0xff; /* 40.000 MHz */ + edid->detailed_timings[0].pixel_clock_msb = 4000 >> 8; edid->detailed_timings[0].h_active_lsb = 800 & 0xff; edid->detailed_timings[0].h_blank_lsb = 256 & 0xff; edid->detailed_timings[0].h_active_blank_msb = ((800 >> 4) & 0xf0) | ((256 >> 8) & 0x0f); From 0fbb94df2ae4226c98f5172d1e15127f94341a0b Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Wed, 25 Nov 2020 17:10:50 -0300 Subject: [PATCH 16/16] More cosmetic changes to DDC --- src/video/vid_ddc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/video/vid_ddc.c b/src/video/vid_ddc.c index 880adc79e..afe80b9ef 100644 --- a/src/video/vid_ddc.c +++ b/src/video/vid_ddc.c @@ -70,7 +70,7 @@ typedef struct { }; } range_limits; struct { - edid_standard_timing_t standard_timings[6]; + edid_standard_timing_t timings[6]; uint8_t padding; } ext_standard_timings; struct { @@ -140,7 +140,9 @@ ddc_init(void *i2c) memset(&edid->established_timings, 0xff, sizeof(edid->established_timings)); /* all enabled */ +#if 0 memset(&edid->standard_timings, 0x01, sizeof(edid->standard_timings)); /* pad unused entries */ +#endif STD_TIMING(0, 1280, STD_ASPECT_16_9); /* 1280x720 */ STD_TIMING(1, 1280, STD_ASPECT_16_10); /* 1280x800 */ STD_TIMING(2, 1366, STD_ASPECT_16_9); /* 1360x768 (closest to 1366x768) */ @@ -150,7 +152,7 @@ ddc_init(void *i2c) STD_TIMING(6, 1920, STD_ASPECT_16_9); /* 1920x1080 */ STD_TIMING(7, 2048, STD_ASPECT_4_3); /* 2048x1536 */ - /* Detailed timings for the preferred mode of 800x600 */ + /* Detailed timings for the preferred mode of 800x600 @ 60 Hz */ edid->detailed_timings[0].pixel_clock_lsb = 4000 & 0xff; /* 40.000 MHz */ edid->detailed_timings[0].pixel_clock_msb = 4000 >> 8; edid->detailed_timings[0].h_active_lsb = 800 & 0xff;