mirror of
https://github.com/86Box/86Box.git
synced 2026-02-24 02:18:20 -07:00
DDC/I2C/SMBus overhaul (incomplete, commit for the night)
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/smbus.h>
|
||||
#include <86box/i2c.h>
|
||||
#include <86box/hwm.h>
|
||||
|
||||
|
||||
@@ -41,17 +41,17 @@ typedef struct {
|
||||
uint16_t regs[32];
|
||||
uint8_t addr_register;
|
||||
|
||||
uint8_t smbus_addr;
|
||||
uint8_t i2c_addr;
|
||||
} gl518sm_t;
|
||||
|
||||
|
||||
static uint8_t gl518sm_smbus_read_byte(uint8_t addr, void *priv);
|
||||
static uint8_t gl518sm_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv);
|
||||
static uint16_t gl518sm_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv);
|
||||
static uint8_t gl518sm_i2c_read_byte(void *bus, uint8_t addr, void *priv);
|
||||
static uint8_t gl518sm_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv);
|
||||
static uint16_t gl518sm_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv);
|
||||
static uint16_t gl518sm_read(gl518sm_t *dev, uint8_t reg);
|
||||
static void gl518sm_smbus_write_byte(uint8_t addr, uint8_t val, void *priv);
|
||||
static void gl518sm_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
|
||||
static void gl518sm_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
|
||||
static void gl518sm_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv);
|
||||
static void gl518sm_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
|
||||
static void gl518sm_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
|
||||
static uint8_t gl518sm_write(gl518sm_t *dev, uint8_t reg, uint16_t val);
|
||||
static void gl518sm_reset(gl518sm_t *dev);
|
||||
|
||||
@@ -79,24 +79,24 @@ gl518sm_log(const char *fmt, ...)
|
||||
static void
|
||||
gl518sm_remap(gl518sm_t *dev, uint8_t addr)
|
||||
{
|
||||
gl518sm_log("GL518SM: remapping to SMBus %02Xh\n", addr);
|
||||
gl518sm_log("GL518SM: remapping to I2C %02Xh\n", addr);
|
||||
|
||||
smbus_removehandler(dev->smbus_addr, 1,
|
||||
gl518sm_smbus_read_byte, gl518sm_smbus_read_byte_cmd, gl518sm_smbus_read_word_cmd, NULL,
|
||||
gl518sm_smbus_write_byte, gl518sm_smbus_write_byte_cmd, gl518sm_smbus_write_word_cmd, NULL,
|
||||
dev);
|
||||
i2c_removehandler(i2c_smbus, dev->i2c_addr, 1,
|
||||
NULL, gl518sm_i2c_read_byte, gl518sm_i2c_read_byte_cmd, gl518sm_i2c_read_word_cmd, NULL,
|
||||
NULL, gl518sm_i2c_write_byte, gl518sm_i2c_write_byte_cmd, gl518sm_i2c_write_word_cmd, NULL,
|
||||
dev);
|
||||
|
||||
if (addr < 0x80) smbus_sethandler(addr, 1,
|
||||
gl518sm_smbus_read_byte, gl518sm_smbus_read_byte_cmd, gl518sm_smbus_read_word_cmd, NULL,
|
||||
gl518sm_smbus_write_byte, gl518sm_smbus_write_byte_cmd, gl518sm_smbus_write_word_cmd, NULL,
|
||||
dev);
|
||||
if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1,
|
||||
NULL, gl518sm_i2c_read_byte, gl518sm_i2c_read_byte_cmd, gl518sm_i2c_read_word_cmd, NULL,
|
||||
NULL, gl518sm_i2c_write_byte, gl518sm_i2c_write_byte_cmd, gl518sm_i2c_write_word_cmd, NULL,
|
||||
dev);
|
||||
|
||||
dev->smbus_addr = addr;
|
||||
dev->i2c_addr = addr;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
gl518sm_smbus_read_byte(uint8_t addr, void *priv)
|
||||
gl518sm_i2c_read_byte(void *bus, uint8_t addr, void *priv)
|
||||
{
|
||||
gl518sm_t *dev = (gl518sm_t *) priv;
|
||||
return gl518sm_read(dev, dev->addr_register);
|
||||
@@ -104,7 +104,7 @@ gl518sm_smbus_read_byte(uint8_t addr, void *priv)
|
||||
|
||||
|
||||
static uint8_t
|
||||
gl518sm_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
gl518sm_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
|
||||
{
|
||||
gl518sm_t *dev = (gl518sm_t *) priv;
|
||||
return gl518sm_read(dev, cmd);
|
||||
@@ -112,7 +112,7 @@ gl518sm_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
|
||||
|
||||
static uint16_t
|
||||
gl518sm_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
gl518sm_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
|
||||
{
|
||||
gl518sm_t *dev = (gl518sm_t *) priv;
|
||||
return gl518sm_read(dev, cmd);
|
||||
@@ -168,7 +168,7 @@ gl518sm_read(gl518sm_t *dev, uint8_t reg)
|
||||
|
||||
|
||||
static void
|
||||
gl518sm_smbus_write_byte(uint8_t addr, uint8_t val, void *priv)
|
||||
gl518sm_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
gl518sm_t *dev = (gl518sm_t *) priv;
|
||||
dev->addr_register = val;
|
||||
@@ -176,7 +176,7 @@ gl518sm_smbus_write_byte(uint8_t addr, uint8_t val, void *priv)
|
||||
|
||||
|
||||
static void
|
||||
gl518sm_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
|
||||
gl518sm_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
|
||||
{
|
||||
gl518sm_t *dev = (gl518sm_t *) priv;
|
||||
gl518sm_write(dev, cmd, val);
|
||||
@@ -184,7 +184,7 @@ gl518sm_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
|
||||
|
||||
|
||||
static void
|
||||
gl518sm_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv)
|
||||
gl518sm_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv)
|
||||
{
|
||||
gl518sm_t *dev = (gl518sm_t *) priv;
|
||||
gl518sm_write(dev, cmd, val);
|
||||
@@ -290,7 +290,7 @@ gl518sm_init(const device_t *info)
|
||||
}
|
||||
|
||||
|
||||
/* GL518SM on SMBus address 2Ch */
|
||||
/* GL518SM on I2C address 2Ch */
|
||||
const device_t gl518sm_2c_device = {
|
||||
"Genesys Logic GL518SM Hardware Monitor",
|
||||
DEVICE_ISA,
|
||||
@@ -300,7 +300,7 @@ const device_t gl518sm_2c_device = {
|
||||
NULL
|
||||
};
|
||||
|
||||
/* GL518SM on SMBus address 2Dh */
|
||||
/* GL518SM on I2C address 2Dh */
|
||||
const device_t gl518sm_2d_device = {
|
||||
"Genesys Logic GL518SM Hardware Monitor",
|
||||
DEVICE_ISA,
|
||||
|
||||
@@ -23,19 +23,19 @@
|
||||
#include <wchar.h>
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/smbus.h>
|
||||
#include <86box/i2c.h>
|
||||
#include <86box/hwm.h>
|
||||
|
||||
|
||||
#define LM75_TEMP_TO_REG(t) ((t) << 8)
|
||||
|
||||
|
||||
static uint8_t lm75_smbus_read_byte(uint8_t addr, void *priv);
|
||||
static uint8_t lm75_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv);
|
||||
static uint16_t lm75_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv);
|
||||
static void lm75_smbus_write_byte(uint8_t addr, uint8_t val, void *priv);
|
||||
static void lm75_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
|
||||
static void lm75_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
|
||||
static uint8_t lm75_i2c_read_byte(void *bus, uint8_t addr, void *priv);
|
||||
static uint8_t lm75_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv);
|
||||
static uint16_t lm75_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv);
|
||||
static void lm75_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv);
|
||||
static void lm75_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
|
||||
static void lm75_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
|
||||
static void lm75_reset(lm75_t *dev);
|
||||
|
||||
|
||||
@@ -62,24 +62,24 @@ lm75_log(const char *fmt, ...)
|
||||
void
|
||||
lm75_remap(lm75_t *dev, uint8_t addr)
|
||||
{
|
||||
lm75_log("LM75: remapping to SMBus %02Xh\n", addr);
|
||||
lm75_log("LM75: remapping to I2C %02Xh\n", addr);
|
||||
|
||||
if (dev->smbus_addr < 0x80) smbus_removehandler(dev->smbus_addr, 1,
|
||||
lm75_smbus_read_byte, lm75_smbus_read_byte_cmd, lm75_smbus_read_word_cmd, NULL,
|
||||
lm75_smbus_write_byte, lm75_smbus_write_byte_cmd, lm75_smbus_write_word_cmd, NULL,
|
||||
dev);
|
||||
if (dev->i2c_addr < 0x80) i2c_removehandler(i2c_smbus, dev->i2c_addr, 1,
|
||||
NULL, lm75_i2c_read_byte, lm75_i2c_read_byte_cmd, lm75_i2c_read_word_cmd, NULL,
|
||||
NULL, lm75_i2c_write_byte, lm75_i2c_write_byte_cmd, lm75_i2c_write_word_cmd, NULL,
|
||||
dev);
|
||||
|
||||
if (addr < 0x80) smbus_sethandler(addr, 1,
|
||||
lm75_smbus_read_byte, lm75_smbus_read_byte_cmd, lm75_smbus_read_word_cmd, NULL,
|
||||
lm75_smbus_write_byte, lm75_smbus_write_byte_cmd, lm75_smbus_write_word_cmd, NULL,
|
||||
dev);
|
||||
if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1,
|
||||
NULL, lm75_i2c_read_byte, lm75_i2c_read_byte_cmd, lm75_i2c_read_word_cmd, NULL,
|
||||
NULL, lm75_i2c_write_byte, lm75_i2c_write_byte_cmd, lm75_i2c_write_word_cmd, NULL,
|
||||
dev);
|
||||
|
||||
dev->smbus_addr = addr;
|
||||
dev->i2c_addr = addr;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
lm75_smbus_read_byte(uint8_t addr, void *priv)
|
||||
lm75_i2c_read_byte(void *bus, uint8_t addr, void *priv)
|
||||
{
|
||||
lm75_t *dev = (lm75_t *) priv;
|
||||
return lm75_read(dev, dev->addr_register);
|
||||
@@ -87,14 +87,14 @@ lm75_smbus_read_byte(uint8_t addr, void *priv)
|
||||
|
||||
|
||||
static uint8_t
|
||||
lm75_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
lm75_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
|
||||
{
|
||||
lm75_t *dev = (lm75_t *) priv;
|
||||
return lm75_read(dev, cmd);
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
lm75_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
lm75_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
|
||||
{
|
||||
lm75_t *dev = (lm75_t *) priv;
|
||||
uint8_t rethi = 0;
|
||||
@@ -129,9 +129,9 @@ lm75_read(lm75_t *dev, uint8_t reg)
|
||||
|
||||
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
|
||||
to access some of its proprietary registers. Pass this operation on to
|
||||
the main monitor address through an internal SMBus call, if necessary. */
|
||||
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_smbus_addr < 0x80))
|
||||
ret = smbus_read_byte_cmd(dev->as99127f_smbus_addr, reg);
|
||||
the main monitor address through an internal I2C call, if necessary. */
|
||||
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80))
|
||||
ret = i2c_read_byte_cmd(i2c_smbus, dev->as99127f_i2c_addr, reg);
|
||||
else if ((reg & 0x7) == 0x0) /* temperature high byte */
|
||||
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]) >> 8;
|
||||
else if ((reg & 0x7) == 0x1) /* temperature low byte */
|
||||
@@ -146,7 +146,7 @@ lm75_read(lm75_t *dev, uint8_t reg)
|
||||
|
||||
|
||||
static void
|
||||
lm75_smbus_write_byte(uint8_t addr, uint8_t val, void *priv)
|
||||
lm75_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
lm75_t *dev = (lm75_t *) priv;
|
||||
dev->addr_register = val;
|
||||
@@ -154,7 +154,7 @@ lm75_smbus_write_byte(uint8_t addr, uint8_t val, void *priv)
|
||||
|
||||
|
||||
static void
|
||||
lm75_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
|
||||
lm75_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
|
||||
{
|
||||
lm75_t *dev = (lm75_t *) priv;
|
||||
lm75_write(dev, cmd, val);
|
||||
@@ -162,7 +162,7 @@ lm75_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
|
||||
|
||||
|
||||
static void
|
||||
lm75_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv)
|
||||
lm75_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv)
|
||||
{
|
||||
lm75_t *dev = (lm75_t *) priv;
|
||||
uint8_t valhi = (val >> 8);
|
||||
@@ -196,9 +196,9 @@ lm75_write(lm75_t *dev, uint8_t reg, uint8_t val)
|
||||
|
||||
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
|
||||
to access some of its proprietary registers. Pass this operation on to
|
||||
the main monitor address through an internal SMBus call, if necessary. */
|
||||
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_smbus_addr < 0x80)) {
|
||||
smbus_write_byte_cmd(dev->as99127f_smbus_addr, reg, val);
|
||||
the main monitor address through an internal I2C call, if necessary. */
|
||||
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
|
||||
i2c_write_byte_cmd(i2c_smbus, dev->as99127f_i2c_addr, reg, val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ lm75_init(const device_t *info)
|
||||
hwm_values.temperatures[dev->local >> 8] = 30;
|
||||
dev->values = &hwm_values;
|
||||
|
||||
dev->as99127f_smbus_addr = 0x80;
|
||||
dev->as99127f_i2c_addr = 0x80;
|
||||
|
||||
lm75_reset(dev);
|
||||
|
||||
|
||||
@@ -25,11 +25,11 @@
|
||||
#include <86box/device.h>
|
||||
#include <86box/io.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/smbus.h>
|
||||
#include <86box/i2c.h>
|
||||
#include <86box/hwm.h>
|
||||
|
||||
|
||||
#define LM78_SMBUS 0x010000
|
||||
#define LM78_I2C 0x010000
|
||||
#define LM78_W83781D 0x020000
|
||||
#define LM78_AS99127F_REV1 0x040000
|
||||
#define LM78_AS99127F_REV2 0x080000
|
||||
@@ -56,19 +56,19 @@ typedef struct {
|
||||
uint8_t addr_register;
|
||||
uint8_t data_register;
|
||||
|
||||
uint8_t smbus_addr;
|
||||
uint8_t i2c_addr;
|
||||
} lm78_t;
|
||||
|
||||
|
||||
static uint8_t lm78_isa_read(uint16_t port, void *priv);
|
||||
static uint8_t lm78_smbus_read_byte(uint8_t addr, void *priv);
|
||||
static uint8_t lm78_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv);
|
||||
static uint16_t lm78_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv);
|
||||
static uint8_t lm78_i2c_read_byte(void *bus, uint8_t addr, void *priv);
|
||||
static uint8_t lm78_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv);
|
||||
static uint16_t lm78_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv);
|
||||
static uint8_t lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank);
|
||||
static void lm78_isa_write(uint16_t port, uint8_t val, void *priv);
|
||||
static void lm78_smbus_write_byte(uint8_t addr, uint8_t val, void *priv);
|
||||
static void lm78_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
|
||||
static void lm78_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
|
||||
static void lm78_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv);
|
||||
static void lm78_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
|
||||
static void lm78_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
|
||||
static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank);
|
||||
static void lm78_reset(lm78_t *dev, uint8_t initialization);
|
||||
|
||||
@@ -98,29 +98,29 @@ lm78_remap(lm78_t *dev, uint8_t addr)
|
||||
{
|
||||
lm75_t *lm75;
|
||||
|
||||
if (!(dev->local & LM78_SMBUS)) return;
|
||||
if (!(dev->local & LM78_I2C)) return;
|
||||
|
||||
lm78_log("LM78: remapping to SMBus %02Xh\n", addr);
|
||||
lm78_log("LM78: remapping to I2C %02Xh\n", addr);
|
||||
|
||||
smbus_removehandler(dev->smbus_addr, 1,
|
||||
lm78_smbus_read_byte, lm78_smbus_read_byte_cmd, lm78_smbus_read_word_cmd, NULL,
|
||||
lm78_smbus_write_byte, lm78_smbus_write_byte_cmd, lm78_smbus_write_word_cmd, NULL,
|
||||
dev);
|
||||
i2c_removehandler(i2c_smbus, dev->i2c_addr, 1,
|
||||
NULL, lm78_i2c_read_byte, lm78_i2c_read_byte_cmd, lm78_i2c_read_word_cmd, NULL,
|
||||
NULL, lm78_i2c_write_byte, lm78_i2c_write_byte_cmd, lm78_i2c_write_word_cmd, NULL,
|
||||
dev);
|
||||
|
||||
if (addr < 0x80) smbus_sethandler(addr, 1,
|
||||
lm78_smbus_read_byte, lm78_smbus_read_byte_cmd, lm78_smbus_read_word_cmd, NULL,
|
||||
lm78_smbus_write_byte, lm78_smbus_write_byte_cmd, lm78_smbus_write_word_cmd, NULL,
|
||||
dev);
|
||||
if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1,
|
||||
NULL, lm78_i2c_read_byte, lm78_i2c_read_byte_cmd, lm78_i2c_read_word_cmd, NULL,
|
||||
NULL, lm78_i2c_write_byte, lm78_i2c_write_byte_cmd, lm78_i2c_write_word_cmd, NULL,
|
||||
dev);
|
||||
|
||||
dev->smbus_addr = addr;
|
||||
dev->i2c_addr = addr;
|
||||
|
||||
if (dev->local & LM78_AS99127F) {
|
||||
/* Store the main SMBus address on the LM75 devices to ensure reads/writes
|
||||
/* Store the main I2C address on the LM75 devices to ensure reads/writes
|
||||
to the AS99127F's proprietary registers are passed through to this side. */
|
||||
for (uint8_t i = 0; i <= 1; i++) {
|
||||
lm75 = device_get_priv(dev->lm75[i]);
|
||||
if (lm75)
|
||||
lm75->as99127f_smbus_addr = dev->smbus_addr;
|
||||
lm75->as99127f_i2c_addr = dev->i2c_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,7 +159,7 @@ lm78_isa_read(uint16_t port, void *priv)
|
||||
|
||||
|
||||
static uint8_t
|
||||
lm78_smbus_read_byte(uint8_t addr, void *priv)
|
||||
lm78_i2c_read_byte(void *bus, uint8_t addr, void *priv)
|
||||
{
|
||||
lm78_t *dev = (lm78_t *) priv;
|
||||
return lm78_read(dev, dev->addr_register, LM78_WINBOND_BANK);
|
||||
@@ -167,7 +167,7 @@ lm78_smbus_read_byte(uint8_t addr, void *priv)
|
||||
|
||||
|
||||
static uint8_t
|
||||
lm78_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
lm78_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
|
||||
{
|
||||
lm78_t *dev = (lm78_t *) priv;
|
||||
return lm78_read(dev, cmd, LM78_WINBOND_BANK);
|
||||
@@ -175,7 +175,7 @@ lm78_smbus_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
|
||||
|
||||
static uint16_t
|
||||
lm78_smbus_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv)
|
||||
lm78_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
|
||||
{
|
||||
lm78_t *dev = (lm78_t *) priv;
|
||||
return (lm78_read(dev, cmd, LM78_WINBOND_BANK) << 8) | lm78_read(dev, cmd, LM78_WINBOND_BANK);
|
||||
@@ -265,7 +265,7 @@ lm78_isa_write(uint16_t port, uint8_t val, void *priv)
|
||||
|
||||
|
||||
static void
|
||||
lm78_smbus_write_byte(uint8_t addr, uint8_t val, void *priv)
|
||||
lm78_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
lm78_t *dev = (lm78_t *) priv;
|
||||
dev->addr_register = val;
|
||||
@@ -273,7 +273,7 @@ lm78_smbus_write_byte(uint8_t addr, uint8_t val, void *priv)
|
||||
|
||||
|
||||
static void
|
||||
lm78_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
|
||||
lm78_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
|
||||
{
|
||||
lm78_t *dev = (lm78_t *) priv;
|
||||
lm78_write(dev, cmd, val, LM78_WINBOND_BANK);
|
||||
@@ -281,7 +281,7 @@ lm78_smbus_write_byte_cmd(uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
|
||||
|
||||
|
||||
static void
|
||||
lm78_smbus_write_word_cmd(uint8_t addr, uint8_t cmd, uint16_t val, void *priv)
|
||||
lm78_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv)
|
||||
{
|
||||
lm78_t *dev = (lm78_t *) priv;
|
||||
lm78_write(dev, cmd, val, LM78_WINBOND_BANK);
|
||||
@@ -354,13 +354,13 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank)
|
||||
|
||||
switch (reg) {
|
||||
case 0x40:
|
||||
if (val & 0x80) /* INITIALIZATION bit resets all registers except main SMBus address */
|
||||
if (val & 0x80) /* INITIALIZATION bit resets all registers except main I2C address */
|
||||
lm78_reset(dev, 1);
|
||||
break;
|
||||
|
||||
case 0x48:
|
||||
/* set main SMBus address */
|
||||
if (dev->local & LM78_SMBUS)
|
||||
/* set main I2C address */
|
||||
if (dev->local & LM78_I2C)
|
||||
lm78_remap(dev, dev->regs[0x48] & 0x7f);
|
||||
break;
|
||||
|
||||
@@ -376,8 +376,8 @@ lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank)
|
||||
break;
|
||||
|
||||
case 0x4a:
|
||||
/* set LM75 SMBus addresses (Winbond only) */
|
||||
if (dev->local & LM78_SMBUS) {
|
||||
/* set LM75 I2C addresses (Winbond only) */
|
||||
if (dev->local & LM78_I2C) {
|
||||
for (uint8_t i = 0; i <= 1; i++) {
|
||||
lm75 = device_get_priv(dev->lm75[i]);
|
||||
if (!lm75)
|
||||
@@ -412,10 +412,10 @@ lm78_reset(lm78_t *dev, uint8_t initialization)
|
||||
dev->regs[0x40] = 0x08;
|
||||
dev->regs[0x46] = 0x40;
|
||||
dev->regs[0x47] = 0x50;
|
||||
if (dev->local & LM78_SMBUS) {
|
||||
if (!initialization) /* don't reset main SMBus address if the reset was triggered by the INITIALIZATION bit */
|
||||
dev->smbus_addr = 0x2d;
|
||||
dev->regs[0x48] = dev->smbus_addr;
|
||||
if (dev->local & LM78_I2C) {
|
||||
if (!initialization) /* don't reset main I2C address if the reset was triggered by the INITIALIZATION bit */
|
||||
dev->i2c_addr = 0x2d;
|
||||
dev->regs[0x48] = dev->i2c_addr;
|
||||
if (dev->local & LM78_WINBOND)
|
||||
dev->regs[0x4a] = 0x01;
|
||||
} else {
|
||||
@@ -469,7 +469,7 @@ lm78_reset(lm78_t *dev, uint8_t initialization)
|
||||
dev->regs[0x49] = 0x40;
|
||||
}
|
||||
|
||||
lm78_remap(dev, dev->smbus_addr);
|
||||
lm78_remap(dev, dev->i2c_addr);
|
||||
}
|
||||
|
||||
|
||||
@@ -519,7 +519,7 @@ lm78_init(const device_t *info)
|
||||
|
||||
/* Set chip-specific default values. */
|
||||
if (dev->local & LM78_AS99127F) {
|
||||
/* AS99127: different -12V Rin value (bruteforced) */
|
||||
/* AS99127: different -12V Rin value (bruteforced) */
|
||||
defaults.voltages[5] = LM78_NEG_VOLTAGE(12000, 2400);
|
||||
} else if (dev->local & LM78_W83782D) {
|
||||
/* W83782D: different negative voltage formula */
|
||||
@@ -536,7 +536,7 @@ lm78_init(const device_t *info)
|
||||
dev->lm75[i] = (device_t *) malloc(sizeof(device_t));
|
||||
memcpy(dev->lm75[i], &lm75_w83781d_device, sizeof(device_t));
|
||||
dev->lm75[i]->local = (i + 1) << 8;
|
||||
if (dev->local & LM78_SMBUS)
|
||||
if (dev->local & LM78_I2C)
|
||||
dev->lm75[i]->local |= 0x48 + i;
|
||||
device_add(dev->lm75[i]);
|
||||
} else {
|
||||
@@ -558,7 +558,7 @@ lm78_init(const device_t *info)
|
||||
const device_t lm78_device = {
|
||||
"National Semiconductor LM78 Hardware Monitor",
|
||||
DEVICE_ISA,
|
||||
0x290 | LM78_SMBUS,
|
||||
0x290 | LM78_I2C,
|
||||
lm78_init, lm78_close, NULL,
|
||||
{ NULL }, NULL, NULL,
|
||||
NULL
|
||||
@@ -569,19 +569,19 @@ const device_t lm78_device = {
|
||||
const device_t w83781d_device = {
|
||||
"Winbond W83781D Hardware Monitor",
|
||||
DEVICE_ISA,
|
||||
0x290 | LM78_SMBUS | LM78_W83781D,
|
||||
0x290 | LM78_I2C | LM78_W83781D,
|
||||
lm78_init, lm78_close, NULL,
|
||||
{ NULL }, NULL, NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
/* The ASUS AS99127F is a customized W83781D with no ISA interface (SMBus
|
||||
/* The ASUS AS99127F is a customized W83781D with no ISA interface (I2C
|
||||
only), added proprietary registers and different chip/vendor IDs. */
|
||||
const device_t as99127f_device = {
|
||||
"ASUS AS99127F Rev. 1 Hardware Monitor",
|
||||
DEVICE_ISA,
|
||||
LM78_SMBUS | LM78_AS99127F_REV1,
|
||||
LM78_I2C | LM78_AS99127F_REV1,
|
||||
lm78_init, lm78_close, NULL,
|
||||
{ NULL }, NULL, NULL,
|
||||
NULL
|
||||
@@ -592,7 +592,7 @@ const device_t as99127f_device = {
|
||||
const device_t as99127f_rev2_device = {
|
||||
"ASUS AS99127F Rev. 2 Hardware Monitor",
|
||||
DEVICE_ISA,
|
||||
LM78_SMBUS | LM78_AS99127F_REV2,
|
||||
LM78_I2C | LM78_AS99127F_REV2,
|
||||
lm78_init, lm78_close, NULL,
|
||||
{ NULL }, NULL, NULL,
|
||||
NULL
|
||||
@@ -603,7 +603,7 @@ const device_t as99127f_rev2_device = {
|
||||
const device_t w83782d_device = {
|
||||
"Winbond W83782D Hardware Monitor",
|
||||
DEVICE_ISA,
|
||||
0x290 | LM78_SMBUS | LM78_W83782D,
|
||||
0x290 | LM78_I2C | LM78_W83782D,
|
||||
lm78_init, lm78_close, NULL,
|
||||
{ NULL }, NULL, NULL,
|
||||
NULL
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/io.h>
|
||||
#include <86box/smbus.h>
|
||||
#include <86box/hwm.h>
|
||||
|
||||
|
||||
|
||||
496
src/device/i2c.c
Normal file
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/device.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/smbus.h>
|
||||
#include <86box/i2c.h>
|
||||
#include <86box/smbus_piix4.h>
|
||||
|
||||
|
||||
@@ -59,22 +59,28 @@ smbus_piix4_read(uint16_t addr, void *priv)
|
||||
case 0x00:
|
||||
ret = dev->stat;
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
dev->index = 0; /* reading from this resets the block data index */
|
||||
ret = dev->ctl;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
ret = dev->cmd;
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
ret = dev->addr;
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
ret = dev->data0;
|
||||
break;
|
||||
|
||||
case 0x06:
|
||||
ret = dev->data1;
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
ret = dev->data[dev->index++];
|
||||
if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE)
|
||||
@@ -82,7 +88,7 @@ smbus_piix4_read(uint16_t addr, void *priv)
|
||||
break;
|
||||
}
|
||||
|
||||
smbus_piix4_log("SMBus PIIX4: read(%02x) = %02x\n", addr, ret);
|
||||
smbus_piix4_log("SMBus PIIX4: read(%02X) = %02x\n", addr, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -95,7 +101,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
|
||||
uint8_t smbus_addr, smbus_read, prev_stat;
|
||||
uint16_t temp;
|
||||
|
||||
smbus_piix4_log("SMBus PIIX4: write(%02x, %02x)\n", addr, val);
|
||||
smbus_piix4_log("SMBus PIIX4: write(%02X, %02X)\n", addr, val);
|
||||
|
||||
prev_stat = dev->next_stat;
|
||||
dev->next_stat = 0;
|
||||
@@ -107,6 +113,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
|
||||
dev->stat &= ~smbus_addr;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
dev->ctl = val & ~(0x40); /* START always reads 0 */
|
||||
if (val & 0x02) { /* cancel an in-progress command if KILL is set */
|
||||
@@ -118,49 +125,53 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
|
||||
}
|
||||
if (val & 0x40) { /* dispatch command if START is set */
|
||||
smbus_addr = (dev->addr >> 1);
|
||||
if (!smbus_has_device(smbus_addr)) {
|
||||
if (!i2c_has_device(i2c_smbus, smbus_addr)) {
|
||||
/* raise DEV_ERR if no device is at this address */
|
||||
dev->next_stat = 0x4;
|
||||
break;
|
||||
}
|
||||
smbus_read = (dev->addr & 0x01);
|
||||
smbus_read = dev->addr & 0x01;
|
||||
|
||||
/* decode the 3-bit command protocol */
|
||||
dev->next_stat = 0x2; /* raise INTER (command completed) by default */
|
||||
switch ((val >> 2) & 0x7) {
|
||||
case 0x0: /* quick R/W */
|
||||
if (smbus_read)
|
||||
i2c_read_quick(i2c_smbus, smbus_addr);
|
||||
else
|
||||
i2c_write_quick(i2c_smbus, smbus_addr);
|
||||
break;
|
||||
|
||||
case 0x1: /* byte R/W */
|
||||
if (smbus_read)
|
||||
dev->data0 = smbus_read_byte(smbus_addr);
|
||||
dev->data0 = i2c_read_byte(i2c_smbus, smbus_addr);
|
||||
else
|
||||
smbus_write_byte(smbus_addr, dev->data0);
|
||||
i2c_write_byte(i2c_smbus, smbus_addr, dev->data0);
|
||||
break;
|
||||
|
||||
case 0x2: /* byte data R/W */
|
||||
if (smbus_read)
|
||||
dev->data0 = smbus_read_byte_cmd(smbus_addr, dev->cmd);
|
||||
dev->data0 = i2c_read_byte_cmd(i2c_smbus, smbus_addr, dev->cmd);
|
||||
else
|
||||
smbus_write_byte_cmd(smbus_addr, dev->cmd, dev->data0);
|
||||
i2c_write_byte_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data0);
|
||||
break;
|
||||
|
||||
case 0x3: /* word data R/W */
|
||||
if (smbus_read) {
|
||||
temp = smbus_read_word_cmd(smbus_addr, dev->cmd);
|
||||
dev->data0 = (temp & 0xFF);
|
||||
dev->data1 = (temp >> 8);
|
||||
temp = i2c_read_word_cmd(i2c_smbus, smbus_addr, dev->cmd);
|
||||
dev->data0 = temp;
|
||||
dev->data1 = temp >> 8;
|
||||
} else {
|
||||
temp = ((dev->data1 << 8) | dev->data0);
|
||||
smbus_write_word_cmd(smbus_addr, dev->cmd, temp);
|
||||
temp = (dev->data1 << 8) | dev->data0;
|
||||
i2c_write_word_cmd(i2c_smbus, smbus_addr, dev->cmd, temp);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x5: /* block R/W */
|
||||
if (smbus_read)
|
||||
dev->data0 = smbus_read_block_cmd(smbus_addr, dev->cmd, dev->data, SMBUS_PIIX4_BLOCK_DATA_SIZE);
|
||||
dev->data0 = i2c_read_block_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data, SMBUS_PIIX4_BLOCK_DATA_SIZE);
|
||||
else
|
||||
smbus_write_block_cmd(smbus_addr, dev->cmd, dev->data, dev->data0);
|
||||
i2c_write_block_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data, dev->data0);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -170,18 +181,23 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
dev->cmd = val;
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
dev->addr = val;
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
dev->data0 = val;
|
||||
break;
|
||||
|
||||
case 0x06:
|
||||
dev->data1 = val;
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
dev->data[dev->index++] = val;
|
||||
if (dev->index >= SMBUS_PIIX4_BLOCK_DATA_SIZE)
|
||||
@@ -189,7 +205,7 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
|
||||
break;
|
||||
}
|
||||
|
||||
/* if a status register update was given, dispatch it after 10ms to ensure nothing breaks */
|
||||
/* if a status register update was given, dispatch it after 10us to ensure nothing breaks */
|
||||
if (dev->next_stat) {
|
||||
dev->stat = 0x1; /* raise HOST_BUSY while waiting */
|
||||
timer_disable(&dev->response_timer);
|
||||
@@ -228,7 +244,8 @@ smbus_piix4_init(const device_t *info)
|
||||
smbus_piix4_t *dev = (smbus_piix4_t *) malloc(sizeof(smbus_piix4_t));
|
||||
memset(dev, 0, sizeof(smbus_piix4_t));
|
||||
|
||||
smbus_init();
|
||||
i2c_smbus = i2c_addbus("smbus_piix4");
|
||||
|
||||
timer_add(&dev->response_timer, smbus_piix4_response, dev, 0);
|
||||
|
||||
return dev;
|
||||
@@ -240,6 +257,9 @@ smbus_piix4_close(void *priv)
|
||||
{
|
||||
smbus_piix4_t *dev = (smbus_piix4_t *) priv;
|
||||
|
||||
i2c_removebus(i2c_smbus);
|
||||
i2c_smbus = NULL;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user