DDC/I2C/SMBus overhaul (incomplete, commit for the night)

This commit is contained in:
RichardG867
2020-11-20 01:22:04 -03:00
parent 833635afaa
commit 886dbe09ea
18 changed files with 1368 additions and 1132 deletions

View File

@@ -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,

View File

@@ -23,19 +23,19 @@
#include <wchar.h>
#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);

View File

@@ -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

View File

@@ -24,7 +24,6 @@
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/smbus.h>
#include <86box/hwm.h>

496
src/device/i2c.c Normal file
View File

@@ -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, <richardg867@gmail.com>
*
* Copyright 2020 RichardG.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#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;
}

277
src/device/i2c_gpio.c Normal file
View File

@@ -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, <http://pcem-emulator.co.uk/>
* RichardG, <richardg867@gmail.com>
*
* Copyright 2008-2020 Sarah Walker.
* Copyright 2020 RichardG.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <wchar.h>
#include <math.h>
#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;
}

View File

@@ -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, <richardg867@gmail.com>
*
* Copyright 2020 RichardG.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#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; c<NADDRS; c++)
smbus[c] = smbus_last[c] = NULL;
smbus_initialized = 1;
}
for (c=0; c<NADDRS; c++) {
if (smbus_last[c]) {
/* Address c has at least one handler. */
p = smbus_last[c];
/* After this loop, p will have the pointer to the first handler. */
while (p) {
q = p->prev;
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;
}

View File

@@ -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);
}

View File

@@ -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;

89
src/include/86box/i2c.h Normal file
View File

@@ -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, <richardg867@gmail.com>
*
* 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*/

View File

@@ -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, <richardg867@gmail.com>
*
* 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*/

View File

@@ -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, <http://pcem-emulator.co.uk/>
* RichardG, <richardg867@gmail.com>
*
* 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*/

View File

@@ -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]);
}
}

View File

@@ -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;
}

View File

@@ -1,6 +1,3 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
/*
* 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, <http://pcem-emulator.co.uk/>
* RichardG, <richardg867@gmail.com>
*
* Copyright 2008-2020 Sarah Walker.
* Copyright 2020 RichardG.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <wchar.h>
#include <math.h>
#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);
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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 \