DDC/I2C/SMBus overhaul (incomplete, commit for the night)
This commit is contained in:
@@ -24,7 +24,7 @@
|
|||||||
#include <86box/86box.h>
|
#include <86box/86box.h>
|
||||||
#include <86box/device.h>
|
#include <86box/device.h>
|
||||||
#include <86box/io.h>
|
#include <86box/io.h>
|
||||||
#include <86box/smbus.h>
|
#include <86box/i2c.h>
|
||||||
#include <86box/hwm.h>
|
#include <86box/hwm.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -41,17 +41,17 @@ typedef struct {
|
|||||||
uint16_t regs[32];
|
uint16_t regs[32];
|
||||||
uint8_t addr_register;
|
uint8_t addr_register;
|
||||||
|
|
||||||
uint8_t smbus_addr;
|
uint8_t i2c_addr;
|
||||||
} gl518sm_t;
|
} gl518sm_t;
|
||||||
|
|
||||||
|
|
||||||
static uint8_t gl518sm_smbus_read_byte(uint8_t addr, void *priv);
|
static uint8_t gl518sm_i2c_read_byte(void *bus, uint8_t addr, void *priv);
|
||||||
static uint8_t gl518sm_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv);
|
static uint8_t gl518sm_i2c_read_byte_cmd(void *bus, 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 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 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_i2c_write_byte(void *bus, 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_i2c_write_byte_cmd(void *bus, 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_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 uint8_t gl518sm_write(gl518sm_t *dev, uint8_t reg, uint16_t val);
|
||||||
static void gl518sm_reset(gl518sm_t *dev);
|
static void gl518sm_reset(gl518sm_t *dev);
|
||||||
|
|
||||||
@@ -79,24 +79,24 @@ gl518sm_log(const char *fmt, ...)
|
|||||||
static void
|
static void
|
||||||
gl518sm_remap(gl518sm_t *dev, uint8_t addr)
|
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,
|
i2c_removehandler(i2c_smbus, dev->i2c_addr, 1,
|
||||||
gl518sm_smbus_read_byte, gl518sm_smbus_read_byte_cmd, gl518sm_smbus_read_word_cmd, NULL,
|
NULL, gl518sm_i2c_read_byte, gl518sm_i2c_read_byte_cmd, gl518sm_i2c_read_word_cmd, NULL,
|
||||||
gl518sm_smbus_write_byte, gl518sm_smbus_write_byte_cmd, gl518sm_smbus_write_word_cmd, NULL,
|
NULL, gl518sm_i2c_write_byte, gl518sm_i2c_write_byte_cmd, gl518sm_i2c_write_word_cmd, NULL,
|
||||||
dev);
|
dev);
|
||||||
|
|
||||||
if (addr < 0x80) smbus_sethandler(addr, 1,
|
if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1,
|
||||||
gl518sm_smbus_read_byte, gl518sm_smbus_read_byte_cmd, gl518sm_smbus_read_word_cmd, NULL,
|
NULL, gl518sm_i2c_read_byte, gl518sm_i2c_read_byte_cmd, gl518sm_i2c_read_word_cmd, NULL,
|
||||||
gl518sm_smbus_write_byte, gl518sm_smbus_write_byte_cmd, gl518sm_smbus_write_word_cmd, NULL,
|
NULL, gl518sm_i2c_write_byte, gl518sm_i2c_write_byte_cmd, gl518sm_i2c_write_word_cmd, NULL,
|
||||||
dev);
|
dev);
|
||||||
|
|
||||||
dev->smbus_addr = addr;
|
dev->i2c_addr = addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint8_t
|
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;
|
gl518sm_t *dev = (gl518sm_t *) priv;
|
||||||
return gl518sm_read(dev, dev->addr_register);
|
return gl518sm_read(dev, dev->addr_register);
|
||||||
@@ -104,7 +104,7 @@ gl518sm_smbus_read_byte(uint8_t addr, void *priv)
|
|||||||
|
|
||||||
|
|
||||||
static uint8_t
|
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;
|
gl518sm_t *dev = (gl518sm_t *) priv;
|
||||||
return gl518sm_read(dev, cmd);
|
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
|
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;
|
gl518sm_t *dev = (gl518sm_t *) priv;
|
||||||
return gl518sm_read(dev, cmd);
|
return gl518sm_read(dev, cmd);
|
||||||
@@ -168,7 +168,7 @@ gl518sm_read(gl518sm_t *dev, uint8_t reg)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
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;
|
gl518sm_t *dev = (gl518sm_t *) priv;
|
||||||
dev->addr_register = val;
|
dev->addr_register = val;
|
||||||
@@ -176,7 +176,7 @@ gl518sm_smbus_write_byte(uint8_t addr, uint8_t val, void *priv)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
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_t *dev = (gl518sm_t *) priv;
|
||||||
gl518sm_write(dev, cmd, val);
|
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
|
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_t *dev = (gl518sm_t *) priv;
|
||||||
gl518sm_write(dev, cmd, val);
|
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 = {
|
const device_t gl518sm_2c_device = {
|
||||||
"Genesys Logic GL518SM Hardware Monitor",
|
"Genesys Logic GL518SM Hardware Monitor",
|
||||||
DEVICE_ISA,
|
DEVICE_ISA,
|
||||||
@@ -300,7 +300,7 @@ const device_t gl518sm_2c_device = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/* GL518SM on SMBus address 2Dh */
|
/* GL518SM on I2C address 2Dh */
|
||||||
const device_t gl518sm_2d_device = {
|
const device_t gl518sm_2d_device = {
|
||||||
"Genesys Logic GL518SM Hardware Monitor",
|
"Genesys Logic GL518SM Hardware Monitor",
|
||||||
DEVICE_ISA,
|
DEVICE_ISA,
|
||||||
|
|||||||
@@ -23,19 +23,19 @@
|
|||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <86box/86box.h>
|
#include <86box/86box.h>
|
||||||
#include <86box/device.h>
|
#include <86box/device.h>
|
||||||
#include <86box/smbus.h>
|
#include <86box/i2c.h>
|
||||||
#include <86box/hwm.h>
|
#include <86box/hwm.h>
|
||||||
|
|
||||||
|
|
||||||
#define LM75_TEMP_TO_REG(t) ((t) << 8)
|
#define LM75_TEMP_TO_REG(t) ((t) << 8)
|
||||||
|
|
||||||
|
|
||||||
static uint8_t lm75_smbus_read_byte(uint8_t addr, void *priv);
|
static uint8_t lm75_i2c_read_byte(void *bus, uint8_t addr, void *priv);
|
||||||
static uint8_t lm75_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv);
|
static uint8_t lm75_i2c_read_byte_cmd(void *bus, 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 uint16_t lm75_i2c_read_word_cmd(void *bus, 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_i2c_write_byte(void *bus, 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_i2c_write_byte_cmd(void *bus, 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 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);
|
static void lm75_reset(lm75_t *dev);
|
||||||
|
|
||||||
|
|
||||||
@@ -62,24 +62,24 @@ lm75_log(const char *fmt, ...)
|
|||||||
void
|
void
|
||||||
lm75_remap(lm75_t *dev, uint8_t addr)
|
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,
|
if (dev->i2c_addr < 0x80) i2c_removehandler(i2c_smbus, dev->i2c_addr, 1,
|
||||||
lm75_smbus_read_byte, lm75_smbus_read_byte_cmd, lm75_smbus_read_word_cmd, NULL,
|
NULL, lm75_i2c_read_byte, lm75_i2c_read_byte_cmd, lm75_i2c_read_word_cmd, NULL,
|
||||||
lm75_smbus_write_byte, lm75_smbus_write_byte_cmd, lm75_smbus_write_word_cmd, NULL,
|
NULL, lm75_i2c_write_byte, lm75_i2c_write_byte_cmd, lm75_i2c_write_word_cmd, NULL,
|
||||||
dev);
|
dev);
|
||||||
|
|
||||||
if (addr < 0x80) smbus_sethandler(addr, 1,
|
if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1,
|
||||||
lm75_smbus_read_byte, lm75_smbus_read_byte_cmd, lm75_smbus_read_word_cmd, NULL,
|
NULL, lm75_i2c_read_byte, lm75_i2c_read_byte_cmd, lm75_i2c_read_word_cmd, NULL,
|
||||||
lm75_smbus_write_byte, lm75_smbus_write_byte_cmd, lm75_smbus_write_word_cmd, NULL,
|
NULL, lm75_i2c_write_byte, lm75_i2c_write_byte_cmd, lm75_i2c_write_word_cmd, NULL,
|
||||||
dev);
|
dev);
|
||||||
|
|
||||||
dev->smbus_addr = addr;
|
dev->i2c_addr = addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint8_t
|
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;
|
lm75_t *dev = (lm75_t *) priv;
|
||||||
return lm75_read(dev, dev->addr_register);
|
return lm75_read(dev, dev->addr_register);
|
||||||
@@ -87,14 +87,14 @@ lm75_smbus_read_byte(uint8_t addr, void *priv)
|
|||||||
|
|
||||||
|
|
||||||
static uint8_t
|
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;
|
lm75_t *dev = (lm75_t *) priv;
|
||||||
return lm75_read(dev, cmd);
|
return lm75_read(dev, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t
|
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;
|
lm75_t *dev = (lm75_t *) priv;
|
||||||
uint8_t rethi = 0;
|
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
|
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
|
||||||
to access some of its proprietary registers. Pass this operation on to
|
to access some of its proprietary registers. Pass this operation on to
|
||||||
the main monitor address through an internal SMBus call, if necessary. */
|
the main monitor address through an internal I2C call, if necessary. */
|
||||||
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_smbus_addr < 0x80))
|
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80))
|
||||||
ret = smbus_read_byte_cmd(dev->as99127f_smbus_addr, reg);
|
ret = i2c_read_byte_cmd(i2c_smbus, dev->as99127f_i2c_addr, reg);
|
||||||
else if ((reg & 0x7) == 0x0) /* temperature high byte */
|
else if ((reg & 0x7) == 0x0) /* temperature high byte */
|
||||||
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]) >> 8;
|
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]) >> 8;
|
||||||
else if ((reg & 0x7) == 0x1) /* temperature low byte */
|
else if ((reg & 0x7) == 0x1) /* temperature low byte */
|
||||||
@@ -146,7 +146,7 @@ lm75_read(lm75_t *dev, uint8_t reg)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
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;
|
lm75_t *dev = (lm75_t *) priv;
|
||||||
dev->addr_register = val;
|
dev->addr_register = val;
|
||||||
@@ -154,7 +154,7 @@ lm75_smbus_write_byte(uint8_t addr, uint8_t val, void *priv)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
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_t *dev = (lm75_t *) priv;
|
||||||
lm75_write(dev, cmd, val);
|
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
|
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;
|
lm75_t *dev = (lm75_t *) priv;
|
||||||
uint8_t valhi = (val >> 8);
|
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
|
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
|
||||||
to access some of its proprietary registers. Pass this operation on to
|
to access some of its proprietary registers. Pass this operation on to
|
||||||
the main monitor address through an internal SMBus call, if necessary. */
|
the main monitor address through an internal I2C call, if necessary. */
|
||||||
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_smbus_addr < 0x80)) {
|
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
|
||||||
smbus_write_byte_cmd(dev->as99127f_smbus_addr, reg, val);
|
i2c_write_byte_cmd(i2c_smbus, dev->as99127f_i2c_addr, reg, val);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +247,7 @@ lm75_init(const device_t *info)
|
|||||||
hwm_values.temperatures[dev->local >> 8] = 30;
|
hwm_values.temperatures[dev->local >> 8] = 30;
|
||||||
dev->values = &hwm_values;
|
dev->values = &hwm_values;
|
||||||
|
|
||||||
dev->as99127f_smbus_addr = 0x80;
|
dev->as99127f_i2c_addr = 0x80;
|
||||||
|
|
||||||
lm75_reset(dev);
|
lm75_reset(dev);
|
||||||
|
|
||||||
|
|||||||
@@ -25,11 +25,11 @@
|
|||||||
#include <86box/device.h>
|
#include <86box/device.h>
|
||||||
#include <86box/io.h>
|
#include <86box/io.h>
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include <86box/smbus.h>
|
#include <86box/i2c.h>
|
||||||
#include <86box/hwm.h>
|
#include <86box/hwm.h>
|
||||||
|
|
||||||
|
|
||||||
#define LM78_SMBUS 0x010000
|
#define LM78_I2C 0x010000
|
||||||
#define LM78_W83781D 0x020000
|
#define LM78_W83781D 0x020000
|
||||||
#define LM78_AS99127F_REV1 0x040000
|
#define LM78_AS99127F_REV1 0x040000
|
||||||
#define LM78_AS99127F_REV2 0x080000
|
#define LM78_AS99127F_REV2 0x080000
|
||||||
@@ -56,19 +56,19 @@ typedef struct {
|
|||||||
uint8_t addr_register;
|
uint8_t addr_register;
|
||||||
uint8_t data_register;
|
uint8_t data_register;
|
||||||
|
|
||||||
uint8_t smbus_addr;
|
uint8_t i2c_addr;
|
||||||
} lm78_t;
|
} lm78_t;
|
||||||
|
|
||||||
|
|
||||||
static uint8_t lm78_isa_read(uint16_t port, void *priv);
|
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_i2c_read_byte(void *bus, uint8_t addr, void *priv);
|
||||||
static uint8_t lm78_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv);
|
static uint8_t lm78_i2c_read_byte_cmd(void *bus, 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 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 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_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_i2c_write_byte(void *bus, 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_i2c_write_byte_cmd(void *bus, 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_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 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);
|
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;
|
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,
|
i2c_removehandler(i2c_smbus, dev->i2c_addr, 1,
|
||||||
lm78_smbus_read_byte, lm78_smbus_read_byte_cmd, lm78_smbus_read_word_cmd, NULL,
|
NULL, lm78_i2c_read_byte, lm78_i2c_read_byte_cmd, lm78_i2c_read_word_cmd, NULL,
|
||||||
lm78_smbus_write_byte, lm78_smbus_write_byte_cmd, lm78_smbus_write_word_cmd, NULL,
|
NULL, lm78_i2c_write_byte, lm78_i2c_write_byte_cmd, lm78_i2c_write_word_cmd, NULL,
|
||||||
dev);
|
dev);
|
||||||
|
|
||||||
if (addr < 0x80) smbus_sethandler(addr, 1,
|
if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1,
|
||||||
lm78_smbus_read_byte, lm78_smbus_read_byte_cmd, lm78_smbus_read_word_cmd, NULL,
|
NULL, lm78_i2c_read_byte, lm78_i2c_read_byte_cmd, lm78_i2c_read_word_cmd, NULL,
|
||||||
lm78_smbus_write_byte, lm78_smbus_write_byte_cmd, lm78_smbus_write_word_cmd, NULL,
|
NULL, lm78_i2c_write_byte, lm78_i2c_write_byte_cmd, lm78_i2c_write_word_cmd, NULL,
|
||||||
dev);
|
dev);
|
||||||
|
|
||||||
dev->smbus_addr = addr;
|
dev->i2c_addr = addr;
|
||||||
|
|
||||||
if (dev->local & LM78_AS99127F) {
|
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. */
|
to the AS99127F's proprietary registers are passed through to this side. */
|
||||||
for (uint8_t i = 0; i <= 1; i++) {
|
for (uint8_t i = 0; i <= 1; i++) {
|
||||||
lm75 = device_get_priv(dev->lm75[i]);
|
lm75 = device_get_priv(dev->lm75[i]);
|
||||||
if (lm75)
|
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
|
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;
|
lm78_t *dev = (lm78_t *) priv;
|
||||||
return lm78_read(dev, dev->addr_register, LM78_WINBOND_BANK);
|
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
|
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;
|
lm78_t *dev = (lm78_t *) priv;
|
||||||
return lm78_read(dev, cmd, LM78_WINBOND_BANK);
|
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
|
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;
|
lm78_t *dev = (lm78_t *) priv;
|
||||||
return (lm78_read(dev, cmd, LM78_WINBOND_BANK) << 8) | lm78_read(dev, cmd, LM78_WINBOND_BANK);
|
return (lm78_read(dev, 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
|
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;
|
lm78_t *dev = (lm78_t *) priv;
|
||||||
dev->addr_register = val;
|
dev->addr_register = val;
|
||||||
@@ -273,7 +273,7 @@ lm78_smbus_write_byte(uint8_t addr, uint8_t val, void *priv)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
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_t *dev = (lm78_t *) priv;
|
||||||
lm78_write(dev, cmd, val, LM78_WINBOND_BANK);
|
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
|
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_t *dev = (lm78_t *) priv;
|
||||||
lm78_write(dev, cmd, val, LM78_WINBOND_BANK);
|
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) {
|
switch (reg) {
|
||||||
case 0x40:
|
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);
|
lm78_reset(dev, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x48:
|
case 0x48:
|
||||||
/* set main SMBus address */
|
/* set main I2C address */
|
||||||
if (dev->local & LM78_SMBUS)
|
if (dev->local & LM78_I2C)
|
||||||
lm78_remap(dev, dev->regs[0x48] & 0x7f);
|
lm78_remap(dev, dev->regs[0x48] & 0x7f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -376,8 +376,8 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x4a:
|
case 0x4a:
|
||||||
/* set LM75 SMBus addresses (Winbond only) */
|
/* set LM75 I2C addresses (Winbond only) */
|
||||||
if (dev->local & LM78_SMBUS) {
|
if (dev->local & LM78_I2C) {
|
||||||
for (uint8_t i = 0; i <= 1; i++) {
|
for (uint8_t i = 0; i <= 1; i++) {
|
||||||
lm75 = device_get_priv(dev->lm75[i]);
|
lm75 = device_get_priv(dev->lm75[i]);
|
||||||
if (!lm75)
|
if (!lm75)
|
||||||
@@ -412,10 +412,10 @@ lm78_reset(lm78_t *dev, uint8_t initialization)
|
|||||||
dev->regs[0x40] = 0x08;
|
dev->regs[0x40] = 0x08;
|
||||||
dev->regs[0x46] = 0x40;
|
dev->regs[0x46] = 0x40;
|
||||||
dev->regs[0x47] = 0x50;
|
dev->regs[0x47] = 0x50;
|
||||||
if (dev->local & LM78_SMBUS) {
|
if (dev->local & LM78_I2C) {
|
||||||
if (!initialization) /* don't reset main SMBus address if the reset was triggered by the INITIALIZATION bit */
|
if (!initialization) /* don't reset main I2C address if the reset was triggered by the INITIALIZATION bit */
|
||||||
dev->smbus_addr = 0x2d;
|
dev->i2c_addr = 0x2d;
|
||||||
dev->regs[0x48] = dev->smbus_addr;
|
dev->regs[0x48] = dev->i2c_addr;
|
||||||
if (dev->local & LM78_WINBOND)
|
if (dev->local & LM78_WINBOND)
|
||||||
dev->regs[0x4a] = 0x01;
|
dev->regs[0x4a] = 0x01;
|
||||||
} else {
|
} else {
|
||||||
@@ -469,7 +469,7 @@ lm78_reset(lm78_t *dev, uint8_t initialization)
|
|||||||
dev->regs[0x49] = 0x40;
|
dev->regs[0x49] = 0x40;
|
||||||
}
|
}
|
||||||
|
|
||||||
lm78_remap(dev, dev->smbus_addr);
|
lm78_remap(dev, dev->i2c_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -536,7 +536,7 @@ lm78_init(const device_t *info)
|
|||||||
dev->lm75[i] = (device_t *) malloc(sizeof(device_t));
|
dev->lm75[i] = (device_t *) malloc(sizeof(device_t));
|
||||||
memcpy(dev->lm75[i], &lm75_w83781d_device, sizeof(device_t));
|
memcpy(dev->lm75[i], &lm75_w83781d_device, sizeof(device_t));
|
||||||
dev->lm75[i]->local = (i + 1) << 8;
|
dev->lm75[i]->local = (i + 1) << 8;
|
||||||
if (dev->local & LM78_SMBUS)
|
if (dev->local & LM78_I2C)
|
||||||
dev->lm75[i]->local |= 0x48 + i;
|
dev->lm75[i]->local |= 0x48 + i;
|
||||||
device_add(dev->lm75[i]);
|
device_add(dev->lm75[i]);
|
||||||
} else {
|
} else {
|
||||||
@@ -558,7 +558,7 @@ lm78_init(const device_t *info)
|
|||||||
const device_t lm78_device = {
|
const device_t lm78_device = {
|
||||||
"National Semiconductor LM78 Hardware Monitor",
|
"National Semiconductor LM78 Hardware Monitor",
|
||||||
DEVICE_ISA,
|
DEVICE_ISA,
|
||||||
0x290 | LM78_SMBUS,
|
0x290 | LM78_I2C,
|
||||||
lm78_init, lm78_close, NULL,
|
lm78_init, lm78_close, NULL,
|
||||||
{ NULL }, NULL, NULL,
|
{ NULL }, NULL, NULL,
|
||||||
NULL
|
NULL
|
||||||
@@ -569,19 +569,19 @@ const device_t lm78_device = {
|
|||||||
const device_t w83781d_device = {
|
const device_t w83781d_device = {
|
||||||
"Winbond W83781D Hardware Monitor",
|
"Winbond W83781D Hardware Monitor",
|
||||||
DEVICE_ISA,
|
DEVICE_ISA,
|
||||||
0x290 | LM78_SMBUS | LM78_W83781D,
|
0x290 | LM78_I2C | LM78_W83781D,
|
||||||
lm78_init, lm78_close, NULL,
|
lm78_init, lm78_close, NULL,
|
||||||
{ NULL }, NULL, NULL,
|
{ 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. */
|
only), added proprietary registers and different chip/vendor IDs. */
|
||||||
const device_t as99127f_device = {
|
const device_t as99127f_device = {
|
||||||
"ASUS AS99127F Rev. 1 Hardware Monitor",
|
"ASUS AS99127F Rev. 1 Hardware Monitor",
|
||||||
DEVICE_ISA,
|
DEVICE_ISA,
|
||||||
LM78_SMBUS | LM78_AS99127F_REV1,
|
LM78_I2C | LM78_AS99127F_REV1,
|
||||||
lm78_init, lm78_close, NULL,
|
lm78_init, lm78_close, NULL,
|
||||||
{ NULL }, NULL, NULL,
|
{ NULL }, NULL, NULL,
|
||||||
NULL
|
NULL
|
||||||
@@ -592,7 +592,7 @@ const device_t as99127f_device = {
|
|||||||
const device_t as99127f_rev2_device = {
|
const device_t as99127f_rev2_device = {
|
||||||
"ASUS AS99127F Rev. 2 Hardware Monitor",
|
"ASUS AS99127F Rev. 2 Hardware Monitor",
|
||||||
DEVICE_ISA,
|
DEVICE_ISA,
|
||||||
LM78_SMBUS | LM78_AS99127F_REV2,
|
LM78_I2C | LM78_AS99127F_REV2,
|
||||||
lm78_init, lm78_close, NULL,
|
lm78_init, lm78_close, NULL,
|
||||||
{ NULL }, NULL, NULL,
|
{ NULL }, NULL, NULL,
|
||||||
NULL
|
NULL
|
||||||
@@ -603,7 +603,7 @@ const device_t as99127f_rev2_device = {
|
|||||||
const device_t w83782d_device = {
|
const device_t w83782d_device = {
|
||||||
"Winbond W83782D Hardware Monitor",
|
"Winbond W83782D Hardware Monitor",
|
||||||
DEVICE_ISA,
|
DEVICE_ISA,
|
||||||
0x290 | LM78_SMBUS | LM78_W83782D,
|
0x290 | LM78_I2C | LM78_W83782D,
|
||||||
lm78_init, lm78_close, NULL,
|
lm78_init, lm78_close, NULL,
|
||||||
{ NULL }, NULL, NULL,
|
{ NULL }, NULL, NULL,
|
||||||
NULL
|
NULL
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include <86box/86box.h>
|
#include <86box/86box.h>
|
||||||
#include <86box/device.h>
|
#include <86box/device.h>
|
||||||
#include <86box/io.h>
|
#include <86box/io.h>
|
||||||
#include <86box/smbus.h>
|
|
||||||
#include <86box/hwm.h>
|
#include <86box/hwm.h>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
496
src/device/i2c.c
Normal file
496
src/device/i2c.c
Normal 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
277
src/device/i2c_gpio.c
Normal 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;
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
#include <86box/io.h>
|
#include <86box/io.h>
|
||||||
#include <86box/device.h>
|
#include <86box/device.h>
|
||||||
#include <86box/timer.h>
|
#include <86box/timer.h>
|
||||||
#include <86box/smbus.h>
|
#include <86box/i2c.h>
|
||||||
#include <86box/smbus_piix4.h>
|
#include <86box/smbus_piix4.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -59,22 +59,28 @@ smbus_piix4_read(uint16_t addr, void *priv)
|
|||||||
case 0x00:
|
case 0x00:
|
||||||
ret = dev->stat;
|
ret = dev->stat;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x02:
|
case 0x02:
|
||||||
dev->index = 0; /* reading from this resets the block data index */
|
dev->index = 0; /* reading from this resets the block data index */
|
||||||
ret = dev->ctl;
|
ret = dev->ctl;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x03:
|
case 0x03:
|
||||||
ret = dev->cmd;
|
ret = dev->cmd;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x04:
|
case 0x04:
|
||||||
ret = dev->addr;
|
ret = dev->addr;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x05:
|
case 0x05:
|
||||||
ret = dev->data0;
|
ret = dev->data0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x06:
|
case 0x06:
|
||||||
ret = dev->data1;
|
ret = dev->data1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x07:
|
case 0x07:
|
||||||
ret = dev->data[dev->index++];
|
ret = dev->data[dev->index++];
|
||||||
if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE)
|
if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE)
|
||||||
@@ -82,7 +88,7 @@ smbus_piix4_read(uint16_t addr, void *priv)
|
|||||||
break;
|
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;
|
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;
|
uint8_t smbus_addr, smbus_read, prev_stat;
|
||||||
uint16_t temp;
|
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;
|
prev_stat = dev->next_stat;
|
||||||
dev->next_stat = 0;
|
dev->next_stat = 0;
|
||||||
@@ -107,6 +113,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
|
|||||||
dev->stat &= ~smbus_addr;
|
dev->stat &= ~smbus_addr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x02:
|
case 0x02:
|
||||||
dev->ctl = val & ~(0x40); /* START always reads 0 */
|
dev->ctl = val & ~(0x40); /* START always reads 0 */
|
||||||
if (val & 0x02) { /* cancel an in-progress command if KILL is set */
|
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 */
|
if (val & 0x40) { /* dispatch command if START is set */
|
||||||
smbus_addr = (dev->addr >> 1);
|
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 */
|
/* raise DEV_ERR if no device is at this address */
|
||||||
dev->next_stat = 0x4;
|
dev->next_stat = 0x4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
smbus_read = (dev->addr & 0x01);
|
smbus_read = dev->addr & 0x01;
|
||||||
|
|
||||||
/* decode the 3-bit command protocol */
|
/* decode the 3-bit command protocol */
|
||||||
dev->next_stat = 0x2; /* raise INTER (command completed) by default */
|
dev->next_stat = 0x2; /* raise INTER (command completed) by default */
|
||||||
switch ((val >> 2) & 0x7) {
|
switch ((val >> 2) & 0x7) {
|
||||||
case 0x0: /* quick R/W */
|
case 0x0: /* quick R/W */
|
||||||
|
if (smbus_read)
|
||||||
|
i2c_read_quick(i2c_smbus, smbus_addr);
|
||||||
|
else
|
||||||
|
i2c_write_quick(i2c_smbus, smbus_addr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x1: /* byte R/W */
|
case 0x1: /* byte R/W */
|
||||||
if (smbus_read)
|
if (smbus_read)
|
||||||
dev->data0 = smbus_read_byte(smbus_addr);
|
dev->data0 = i2c_read_byte(i2c_smbus, smbus_addr);
|
||||||
else
|
else
|
||||||
smbus_write_byte(smbus_addr, dev->data0);
|
i2c_write_byte(i2c_smbus, smbus_addr, dev->data0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x2: /* byte data R/W */
|
case 0x2: /* byte data R/W */
|
||||||
if (smbus_read)
|
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
|
else
|
||||||
smbus_write_byte_cmd(smbus_addr, dev->cmd, dev->data0);
|
i2c_write_byte_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x3: /* word data R/W */
|
case 0x3: /* word data R/W */
|
||||||
if (smbus_read) {
|
if (smbus_read) {
|
||||||
temp = smbus_read_word_cmd(smbus_addr, dev->cmd);
|
temp = i2c_read_word_cmd(i2c_smbus, smbus_addr, dev->cmd);
|
||||||
dev->data0 = (temp & 0xFF);
|
dev->data0 = temp;
|
||||||
dev->data1 = (temp >> 8);
|
dev->data1 = temp >> 8;
|
||||||
} else {
|
} else {
|
||||||
temp = ((dev->data1 << 8) | dev->data0);
|
temp = (dev->data1 << 8) | dev->data0;
|
||||||
smbus_write_word_cmd(smbus_addr, dev->cmd, temp);
|
i2c_write_word_cmd(i2c_smbus, smbus_addr, dev->cmd, temp);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x5: /* block R/W */
|
case 0x5: /* block R/W */
|
||||||
if (smbus_read)
|
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
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -170,18 +181,23 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x03:
|
case 0x03:
|
||||||
dev->cmd = val;
|
dev->cmd = val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x04:
|
case 0x04:
|
||||||
dev->addr = val;
|
dev->addr = val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x05:
|
case 0x05:
|
||||||
dev->data0 = val;
|
dev->data0 = val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x06:
|
case 0x06:
|
||||||
dev->data1 = val;
|
dev->data1 = val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x07:
|
case 0x07:
|
||||||
dev->data[dev->index++] = val;
|
dev->data[dev->index++] = val;
|
||||||
if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE)
|
if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE)
|
||||||
@@ -189,7 +205,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
|
|||||||
break;
|
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) {
|
if (dev->next_stat) {
|
||||||
dev->stat = 0x1; /* raise HOST_BUSY while waiting */
|
dev->stat = 0x1; /* raise HOST_BUSY while waiting */
|
||||||
timer_disable(&dev->response_timer);
|
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));
|
smbus_piix4_t *dev = (smbus_piix4_t *) malloc(sizeof(smbus_piix4_t));
|
||||||
memset(dev, 0, 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);
|
timer_add(&dev->response_timer, smbus_piix4_response, dev, 0);
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
@@ -240,6 +257,9 @@ smbus_piix4_close(void *priv)
|
|||||||
{
|
{
|
||||||
smbus_piix4_t *dev = (smbus_piix4_t *) priv;
|
smbus_piix4_t *dev = (smbus_piix4_t *) priv;
|
||||||
|
|
||||||
|
i2c_removebus(i2c_smbus);
|
||||||
|
i2c_smbus = NULL;
|
||||||
|
|
||||||
free(dev);
|
free(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ typedef struct {
|
|||||||
uint8_t regs[8];
|
uint8_t regs[8];
|
||||||
uint8_t addr_register;
|
uint8_t addr_register;
|
||||||
uint8_t temp_idx;
|
uint8_t temp_idx;
|
||||||
uint8_t smbus_addr;
|
uint8_t i2c_addr;
|
||||||
|
|
||||||
uint8_t as99127f_smbus_addr;
|
uint8_t as99127f_i2c_addr;
|
||||||
} lm75_t;
|
} lm75_t;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
89
src/include/86box/i2c.h
Normal file
89
src/include/86box/i2c.h
Normal 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*/
|
||||||
@@ -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*/
|
|
||||||
@@ -1,4 +1,24 @@
|
|||||||
void ddc_init(void);
|
/*
|
||||||
void ddc_i2c_change(int new_clock, int new_data);
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||||
int ddc_read_clock(void);
|
* running old operating systems and software designed for IBM
|
||||||
int ddc_read_data(void);
|
* 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*/
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#define HAVE_STDARG_H
|
#define HAVE_STDARG_H
|
||||||
#include <86box/86box.h>
|
#include <86box/86box.h>
|
||||||
#include <86box/device.h>
|
#include <86box/device.h>
|
||||||
#include <86box/smbus.h>
|
#include <86box/i2c.h>
|
||||||
#include <86box/spd.h>
|
#include <86box/spd.h>
|
||||||
#include <86box/version.h>
|
#include <86box/version.h>
|
||||||
#include <86box/machine.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];
|
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
|
#ifdef ENABLE_SPD_LOG
|
||||||
int spd_do_log = ENABLE_SPD_LOG;
|
int spd_do_log = ENABLE_SPD_LOG;
|
||||||
|
|
||||||
@@ -63,15 +58,7 @@ spd_log(const char *fmt, ...)
|
|||||||
|
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
spd_read_byte(uint8_t addr, void *priv)
|
spd_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, 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_t *dev = (spd_t *) priv;
|
spd_t *dev = (spd_t *) priv;
|
||||||
uint8_t ret = *(spd_data[dev->slot] + cmd);
|
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
|
uint8_t
|
||||||
spd_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
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
|
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;
|
uint8_t read = 0;
|
||||||
for (uint8_t i = cmd; i < len && i < SPD_DATA_SIZE; i++) {
|
for (uint8_t i = cmd; (i < len) && (i < SPD_DATA_SIZE); i++)
|
||||||
data[read++] = spd_read_byte_cmd(addr, i, priv);
|
data[read++] = spd_read_byte_cmd(bus, addr, i, priv);
|
||||||
}
|
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
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;
|
spd_t *dev = (spd_t *) priv;
|
||||||
dev->addr_register = val;
|
dev->addr_register = val;
|
||||||
@@ -111,11 +105,11 @@ spd_close(void *priv)
|
|||||||
{
|
{
|
||||||
spd_t *dev = (spd_t *) 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,
|
i2c_removehandler(i2c_smbus, SPD_BASE_ADDR + dev->slot, 1,
|
||||||
spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd,
|
NULL, spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd,
|
||||||
spd_write_byte, NULL, NULL, NULL,
|
NULL, spd_write_byte, NULL, NULL, NULL,
|
||||||
dev);
|
dev);
|
||||||
|
|
||||||
spd_present = 0;
|
spd_present = 0;
|
||||||
@@ -129,11 +123,11 @@ spd_init(const device_t *info)
|
|||||||
{
|
{
|
||||||
spd_t *dev = spd_devices[info->local];
|
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,
|
i2c_sethandler(i2c_smbus, SPD_BASE_ADDR + dev->slot, 1,
|
||||||
spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd,
|
NULL, spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd,
|
||||||
spd_write_byte, NULL, NULL, NULL,
|
NULL, spd_write_byte, NULL, NULL, NULL,
|
||||||
dev);
|
dev);
|
||||||
|
|
||||||
spd_present = 1;
|
spd_present = 1;
|
||||||
@@ -171,7 +165,7 @@ spd_populate(uint16_t *vslots, uint8_t slot_count, uint16_t total_size, uint16_t
|
|||||||
memset(vslots, 0x00, SPD_MAX_SLOTS << 1);
|
memset(vslots, 0x00, SPD_MAX_SLOTS << 1);
|
||||||
for (vslot = 0; vslot < slot_count && total_size; vslot++) {
|
for (vslot = 0; vslot < slot_count && total_size; vslot++) {
|
||||||
/* populate slot */
|
/* populate slot */
|
||||||
vslots[vslot] = (1 << log2_ui16(MIN(total_size, max_module_size)));
|
vslots[vslot] = 1 << log2_ui16(MIN(total_size, max_module_size));
|
||||||
if (total_size >= vslots[vslot]) {
|
if (total_size >= vslots[vslot]) {
|
||||||
spd_log("SPD: initial vslot %d = %d MB\n", vslot, vslots[vslot]);
|
spd_log("SPD: initial vslot %d = %d MB\n", vslot, vslots[vslot]);
|
||||||
total_size -= vslots[vslot];
|
total_size -= vslots[vslot];
|
||||||
@@ -218,8 +212,8 @@ spd_populate(uint16_t *vslots, uint8_t slot_count, uint16_t total_size, uint16_t
|
|||||||
break; /* no empty vslots left */
|
break; /* no empty vslots left */
|
||||||
|
|
||||||
/* split the module into its own vslot and the next empty vslot */
|
/* 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));
|
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);
|
vslots[vslot] = vslots[next_empty_vslot] = vslots[vslot] >> 1;
|
||||||
split = 1;
|
split = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -252,7 +246,7 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
spd_log("SPD: unknown RAM type 0x%02X\n", ram_type);
|
spd_log("SPD: unknown RAM type %02X\n", ram_type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,11 +282,11 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size)
|
|||||||
spd_devices[slot]->size = vslots[vslot];
|
spd_devices[slot]->size = vslots[vslot];
|
||||||
|
|
||||||
/* determine the second row size, from which the first row size can be obtained */
|
/* 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 */
|
asym = vslots[vslot] - (1 << log2_ui16(vslots[vslot])); /* separate the powers of 2 */
|
||||||
if (!asym) /* is the module asymmetric? */
|
if (!asym) /* is the module asymmetric? */
|
||||||
asym = (vslots[vslot] >> 1); /* symmetric, therefore divide by 2 */
|
asym = vslots[vslot] >> 1; /* symmetric, therefore divide by 2 */
|
||||||
|
|
||||||
spd_devices[slot]->row1 = (vslots[vslot] - asym);
|
spd_devices[slot]->row1 = vslots[vslot] - asym;
|
||||||
spd_devices[slot]->row2 = 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);
|
||||||
@@ -312,8 +306,8 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size)
|
|||||||
edo_data->row_bits = SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row1)); /* first row */
|
edo_data->row_bits = SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row1)); /* first row */
|
||||||
edo_data->col_bits = 9;
|
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 */
|
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->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->col_bits |= 9 << 4; /* same as first row, but just in case */
|
||||||
}
|
}
|
||||||
edo_data->banks = 2;
|
edo_data->banks = 2;
|
||||||
edo_data->data_width_lsb = 64;
|
edo_data->data_width_lsb = 64;
|
||||||
@@ -348,8 +342,8 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size)
|
|||||||
sdram_data->row_bits = SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row1)); /* first row */
|
sdram_data->row_bits = SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row1)); /* first row */
|
||||||
sdram_data->col_bits = 9;
|
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 */
|
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->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->col_bits |= 9 << 4; /* same as first row, but just in case */
|
||||||
}
|
}
|
||||||
sdram_data->rows = 2;
|
sdram_data->rows = 2;
|
||||||
sdram_data->data_width_lsb = 64;
|
sdram_data->data_width_lsb = 64;
|
||||||
@@ -370,10 +364,10 @@ spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size)
|
|||||||
sdram_data->trp = sdram_data->trrd = sdram_data->trcd = sdram_data->tras = 1;
|
sdram_data->trp = sdram_data->trrd = sdram_data->trcd = sdram_data->tras = 1;
|
||||||
if (spd_devices[slot]->row1 != spd_devices[slot]->row2) {
|
if (spd_devices[slot]->row1 != spd_devices[slot]->row2) {
|
||||||
/* Utilities interpret bank_density a bit differently on asymmetric modules. */
|
/* 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]->row1 >> 1) - 2); /* first row */
|
||||||
sdram_data->bank_density |= (1 << (log2_ui16(spd_devices[slot]->row2 >> 1) - 2)); /* second row */
|
sdram_data->bank_density |= 1 << (log2_ui16(spd_devices[slot]->row2 >> 1) - 2); /* second row */
|
||||||
} else {
|
} else {
|
||||||
sdram_data->bank_density = (1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 1)); /* symmetric module = only one bit is set */
|
sdram_data->bank_density = 1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 1); /* symmetric module = only one bit is set */
|
||||||
}
|
}
|
||||||
sdram_data->ca_setup = sdram_data->data_setup = 0x15;
|
sdram_data->ca_setup = sdram_data->data_setup = 0x15;
|
||||||
sdram_data->ca_hold = sdram_data->data_hold = 0x08;
|
sdram_data->ca_hold = sdram_data->data_hold = 0x08;
|
||||||
@@ -418,7 +412,7 @@ spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit
|
|||||||
/* No SPD: split SIMMs into pairs as if they were "DIMM"s. */
|
/* No SPD: split SIMMs into pairs as if they were "DIMM"s. */
|
||||||
if (!spd_present) {
|
if (!spd_present) {
|
||||||
dimm = ((reg_max - reg_min) + 1) >> 1; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */
|
dimm = ((reg_max - reg_min) + 1) >> 1; /* amount of "DIMM"s, also used to determine the maximum "DIMM" size */
|
||||||
spd_populate(vslots, dimm, (mem_size >> 10), drb_unit, 1 << (log2_ui16(machines[machine].max_ram / dimm)), 0);
|
spd_populate(vslots, dimm, mem_size >> 10, drb_unit, 1 << (log2_ui16(machines[machine].max_ram / dimm)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write DRBs for each row. */
|
/* Write DRBs for each row. */
|
||||||
@@ -431,9 +425,9 @@ spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit
|
|||||||
/* SPD enabled: use SPD info for this slot, if present. */
|
/* SPD enabled: use SPD info for this slot, if present. */
|
||||||
if (spd_devices[dimm]) {
|
if (spd_devices[dimm]) {
|
||||||
if (spd_devices[dimm]->row1 < drb_unit) /* hack within a hack: turn a double-sided DIMM that is too small into a single-sided one */
|
if (spd_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);
|
size = (row & 1) ? 0 : drb_unit;
|
||||||
else
|
else
|
||||||
size = ((row & 1) ? spd_devices[dimm]->row2 : spd_devices[dimm]->row1);
|
size = (row & 1) ? spd_devices[dimm]->row2 : spd_devices[dimm]->row1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* No SPD: use the values calculated above. */
|
/* No SPD: use the values calculated above. */
|
||||||
@@ -442,7 +436,7 @@ spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit
|
|||||||
|
|
||||||
/* Determine the DRB register to write. */
|
/* Determine the DRB register to write. */
|
||||||
drb = reg_min + row;
|
drb = reg_min + row;
|
||||||
if ((apollo) && ((drb & 0xf) < 0xa))
|
if (apollo && ((drb & 0xf) < 0xa))
|
||||||
drb = apollo + (drb & 0xf);
|
drb = apollo + (drb & 0xf);
|
||||||
|
|
||||||
/* Write DRB register, adding the previous DRB's value. */
|
/* Write DRB register, adding the previous DRB's value. */
|
||||||
@@ -453,7 +447,7 @@ spd_write_drbs(uint8_t *regs, uint8_t reg_min, uint8_t reg_max, uint8_t drb_unit
|
|||||||
else
|
else
|
||||||
regs[drb] = regs[drb - 1];
|
regs[drb] = regs[drb - 1];
|
||||||
if (size)
|
if (size)
|
||||||
regs[drb] += (size / drb_unit); /* this will intentionally overflow on 440GX with 2 GB */
|
regs[drb] += size / drb_unit; /* this will intentionally overflow on 440GX with 2 GB */
|
||||||
spd_log("DRB[%d] = %d MB (%02Xh raw)\n", row, size, regs[drb]);
|
spd_log("DRB[%d] = %d MB (%02Xh raw)\n", row, size, regs[drb]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include <86box/rom.h>
|
#include <86box/rom.h>
|
||||||
#include <86box/plat.h>
|
#include <86box/plat.h>
|
||||||
#include <86box/video.h>
|
#include <86box/video.h>
|
||||||
|
#include <86box/i2c.h>
|
||||||
#include <86box/vid_ddc.h>
|
#include <86box/vid_ddc.h>
|
||||||
#include <86box/vid_svga.h>
|
#include <86box/vid_svga.h>
|
||||||
#include <86box/vid_svga_render.h>
|
#include <86box/vid_svga_render.h>
|
||||||
@@ -251,6 +252,8 @@ typedef struct mach64_t
|
|||||||
uint32_t buf_offset[2], buf_pitch[2];
|
uint32_t buf_offset[2], buf_pitch[2];
|
||||||
|
|
||||||
int overlay_v_acc;
|
int overlay_v_acc;
|
||||||
|
|
||||||
|
void *i2c;
|
||||||
} mach64_t;
|
} mach64_t;
|
||||||
|
|
||||||
static video_timings_t timing_mach64_isa = {VIDEO_ISA, 3, 3, 6, 5, 5, 10};
|
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;
|
mach64_t *mach64 = (mach64_t *)p;
|
||||||
uint8_t gpio_state;
|
uint8_t gpio_state;
|
||||||
|
|
||||||
uint8_t ret;
|
uint8_t ret = 0xff;
|
||||||
if (!(addr & 0x400))
|
if (!(addr & 0x400))
|
||||||
{
|
{
|
||||||
mach64_log("nmach64_ext_readb: addr=%04x\n", addr);
|
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)))
|
if ((ret & (1 << 4)) && !(ret & (1 << 1)))
|
||||||
gpio_state &= ~(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);
|
gpio_state &= ~(1 << 1);
|
||||||
if ((ret & (1 << 5)) && !(ret & (1 << 2)))
|
if ((ret & (1 << 5)) && !(ret & (1 << 2)))
|
||||||
gpio_state &= ~(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);
|
gpio_state &= ~(1 << 2);
|
||||||
|
|
||||||
ret = (ret & ~6) | gpio_state;
|
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);
|
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;
|
data = (val & (1 << 4)) ? ((val & (1 << 1)) ? 1 : 0) : 1;
|
||||||
clk = (val & (1 << 5)) ? ((val & (1 << 2)) ? 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;
|
break;
|
||||||
|
|
||||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
|
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_not_full_event = thread_create_event();
|
||||||
mach64->fifo_thread = thread_create(fifo_thread, mach64);
|
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;
|
return mach64;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
/*
|
/*
|
||||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||||
* running old operating systems and software designed for IBM
|
* running old operating systems and software designed for IBM
|
||||||
@@ -14,35 +11,43 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||||
|
* RichardG, <richardg867@gmail.com>
|
||||||
*
|
*
|
||||||
* Copyright 2008-2020 Sarah Walker.
|
* Copyright 2008-2020 Sarah Walker.
|
||||||
|
* Copyright 2020 RichardG.
|
||||||
*/
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <86box/86box.h>
|
#include <86box/86box.h>
|
||||||
#include "cpu.h"
|
#include <86box/i2c.h>
|
||||||
#include <86box/vid_ddc.h>
|
|
||||||
|
|
||||||
|
|
||||||
static uint8_t edid_data[128] =
|
typedef struct {
|
||||||
{
|
uint8_t addr_register;
|
||||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /*Fixed header pattern*/
|
} ddc_t;
|
||||||
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)*/
|
|
||||||
|
|
||||||
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*/
|
static uint8_t edid_data[128] = {
|
||||||
0x00, 0x00, /*Standard timing information*/
|
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) */
|
||||||
|
|
||||||
|
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 */
|
||||||
|
|
||||||
|
0xff, 0xff, 0xff, /* Established timing bitmap */
|
||||||
|
0x00, 0x00, /* Standard timing information */
|
||||||
0x00, 0x00,
|
0x00, 0x00,
|
||||||
0x00, 0x00,
|
0x00, 0x00,
|
||||||
0x00, 0x00,
|
0x00, 0x00,
|
||||||
@@ -51,7 +56,7 @@ static uint8_t edid_data[128] =
|
|||||||
0x00, 0x00,
|
0x00, 0x00,
|
||||||
0x00, 0x00,
|
0x00, 0x00,
|
||||||
|
|
||||||
/*Detailed mode descriptions*/
|
/* 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,
|
||||||
|
|
||||||
@@ -64,271 +69,64 @@ static uint8_t edid_data[128] =
|
|||||||
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, /* No extensions */
|
||||||
0x00
|
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,
|
return edid_data[cmd & 0x7f];
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
ddc_t *dev = (ddc_t *) priv;
|
||||||
i2c.byte = edid_data[(prom.addr++) & 0x7F];
|
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);
|
return (ddc_read_byte_cmd(bus, addr, cmd + 1, priv) << 8) | ddc_read_byte_cmd(bus, addr, cmd, priv);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
uint8_t read = 0;
|
||||||
switch (i2c.state)
|
for (uint8_t i = cmd; (i < len) && (i < 0x80); i++)
|
||||||
{
|
data[read++] = ddc_read_byte_cmd(bus, addr, i, priv);
|
||||||
case I2C_IDLE:
|
return read;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ddc_read_clock(void)
|
|
||||||
|
void
|
||||||
|
ddc_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv)
|
||||||
{
|
{
|
||||||
return i2c.clock;
|
ddc_t *dev = (ddc_t *) priv;
|
||||||
}
|
dev->addr_register = val;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ddc_init(void)
|
|
||||||
|
void
|
||||||
|
ddc_init(void *i2c)
|
||||||
{
|
{
|
||||||
int c;
|
ddc_t *dev = (ddc_t *) malloc(sizeof(ddc_t));
|
||||||
|
memset(dev, 0, sizeof(ddc_t));
|
||||||
|
|
||||||
uint8_t checksum = 0;
|
uint8_t checksum = 0;
|
||||||
|
for (int c = 0; c < 127; c++)
|
||||||
for (c = 0; c < 127; c++)
|
|
||||||
checksum += edid_data[c];
|
checksum += edid_data[c];
|
||||||
edid_data[127] = 256 - checksum;
|
edid_data[127] = 256 - checksum;
|
||||||
|
|
||||||
i2c.clock = 1;
|
i2c_sethandler(i2c, 0x50, 1,
|
||||||
i2c.data = 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include <86box/device.h>
|
#include <86box/device.h>
|
||||||
#include <86box/plat.h>
|
#include <86box/plat.h>
|
||||||
#include <86box/video.h>
|
#include <86box/video.h>
|
||||||
|
#include <86box/i2c.h>
|
||||||
#include <86box/vid_ddc.h>
|
#include <86box/vid_ddc.h>
|
||||||
#include <86box/vid_svga.h>
|
#include <86box/vid_svga.h>
|
||||||
#include <86box/vid_svga_render.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 subsys_stat, subsys_cntl, advfunc_cntl;
|
||||||
|
|
||||||
uint8_t serialport;
|
uint8_t serialport;
|
||||||
|
|
||||||
|
void *i2c;
|
||||||
} virge_t;
|
} virge_t;
|
||||||
|
|
||||||
static video_timings_t timing_diamond_stealth3d_2000_vlb = {VIDEO_BUS, 2, 2, 3, 28, 28, 45};
|
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:
|
case 0xff20: case 0xff21:
|
||||||
ret = virge->serialport & ~(SERIAL_PORT_SCR | SERIAL_PORT_SDR);
|
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;
|
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;
|
ret |= SERIAL_PORT_SDR;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -1180,7 +1183,7 @@ static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p)
|
|||||||
|
|
||||||
case 0xff20:
|
case 0xff20:
|
||||||
virge->serialport = val;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3845,7 +3848,8 @@ static void *s3_virge_init(const device_t *info)
|
|||||||
virge->fifo_not_full_event = thread_create_event();
|
virge->fifo_not_full_event = thread_create_event();
|
||||||
virge->fifo_thread = thread_create(fifo_thread, virge);
|
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;
|
return virge;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include <86box/device.h>
|
#include <86box/device.h>
|
||||||
#include <86box/plat.h>
|
#include <86box/plat.h>
|
||||||
#include <86box/video.h>
|
#include <86box/video.h>
|
||||||
|
#include <86box/i2c.h>
|
||||||
#include <86box/vid_ddc.h>
|
#include <86box/vid_ddc.h>
|
||||||
#include <86box/vid_svga.h>
|
#include <86box/vid_svga.h>
|
||||||
#include <86box/vid_svga_render.h>
|
#include <86box/vid_svga_render.h>
|
||||||
@@ -116,6 +117,8 @@ typedef struct banshee_t
|
|||||||
uint32_t desktop_stride_tiled;
|
uint32_t desktop_stride_tiled;
|
||||||
|
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
|
void *i2c;
|
||||||
} banshee_t;
|
} banshee_t;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@@ -682,7 +685,7 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p)
|
|||||||
case Video_vidSerialParallelPort:
|
case Video_vidSerialParallelPort:
|
||||||
banshee->vidSerialParallelPort = val;
|
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);
|
// 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;
|
break;
|
||||||
|
|
||||||
case Video_vidScreenSize:
|
case Video_vidScreenSize:
|
||||||
@@ -915,9 +918,9 @@ static uint32_t banshee_ext_inl(uint16_t addr, void *p)
|
|||||||
|
|
||||||
case Video_vidSerialParallelPort:
|
case Video_vidSerialParallelPort:
|
||||||
ret = banshee->vidSerialParallelPort & ~(VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R);
|
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;
|
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 |= VIDSERIAL_DDC_DDA_R;
|
||||||
ret = ret & ~(VIDSERIAL_I2C_SCK_R | VIDSERIAL_I2C_SDA_R);
|
ret = ret & ~(VIDSERIAL_I2C_SCK_R | VIDSERIAL_I2C_SDA_R);
|
||||||
if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SCK_W)
|
if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SCK_W)
|
||||||
@@ -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;
|
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);
|
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_banshee);
|
||||||
|
|
||||||
@@ -2672,6 +2676,7 @@ static void banshee_close(void *p)
|
|||||||
|
|
||||||
voodoo_card_close(banshee->voodoo);
|
voodoo_card_close(banshee->voodoo);
|
||||||
svga_close(&banshee->svga);
|
svga_close(&banshee->svga);
|
||||||
|
i2c_gpio_close(banshee->i2c);
|
||||||
|
|
||||||
free(banshee);
|
free(banshee);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 \
|
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 \
|
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.o \
|
||||||
keyboard_xt.o keyboard_at.o \
|
keyboard_xt.o keyboard_at.o \
|
||||||
mouse.o \
|
mouse.o \
|
||||||
|
|||||||
Reference in New Issue
Block a user