From 886dbe09ea48eeed45053d67fc3fde866a2c90c8 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 20 Nov 2020 01:22:04 -0300 Subject: [PATCH] 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 \