I2C overhaul part 2

This commit is contained in:
RichardG867
2020-11-20 19:23:14 -03:00
parent 886dbe09ea
commit 739fdc46cc
20 changed files with 430 additions and 641 deletions

View File

@@ -41,17 +41,14 @@ typedef struct {
uint16_t regs[32];
uint8_t addr_register;
uint8_t i2c_addr;
uint8_t i2c_addr, i2c_state;
} gl518sm_t;
static uint8_t gl518sm_i2c_read_byte(void *bus, uint8_t addr, void *priv);
static uint8_t gl518sm_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv);
static uint16_t gl518sm_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv);
static void gl518sm_i2c_start(void *bus, uint8_t addr, void *priv);
static uint8_t gl518sm_i2c_read(void *bus, uint8_t addr, void *priv);
static uint16_t gl518sm_read(gl518sm_t *dev, uint8_t reg);
static void gl518sm_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv);
static void gl518sm_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
static void gl518sm_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
static uint8_t gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv);
static uint8_t gl518sm_write(gl518sm_t *dev, uint8_t reg, uint16_t val);
static void gl518sm_reset(gl518sm_t *dev);
@@ -81,41 +78,40 @@ gl518sm_remap(gl518sm_t *dev, uint8_t addr)
{
gl518sm_log("GL518SM: remapping to I2C %02Xh\n", addr);
i2c_removehandler(i2c_smbus, dev->i2c_addr, 1,
NULL, gl518sm_i2c_read_byte, gl518sm_i2c_read_byte_cmd, gl518sm_i2c_read_word_cmd, NULL,
NULL, gl518sm_i2c_write_byte, gl518sm_i2c_write_byte_cmd, gl518sm_i2c_write_word_cmd, NULL,
dev);
i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, gl518sm_i2c_start, gl518sm_i2c_read, gl518sm_i2c_write, NULL, dev);
if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1,
NULL, gl518sm_i2c_read_byte, gl518sm_i2c_read_byte_cmd, gl518sm_i2c_read_word_cmd, NULL,
NULL, gl518sm_i2c_write_byte, gl518sm_i2c_write_byte_cmd, gl518sm_i2c_write_word_cmd, NULL,
dev);
if (addr < 0x80)
i2c_sethandler(i2c_smbus, addr, 1, gl518sm_i2c_start, gl518sm_i2c_read, gl518sm_i2c_write, NULL, dev);
dev->i2c_addr = addr;
}
static uint8_t
gl518sm_i2c_read_byte(void *bus, uint8_t addr, void *priv)
static void
gl518sm_i2c_start(void *bus, uint8_t addr, void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
return gl518sm_read(dev, dev->addr_register);
dev->i2c_state = 0;
}
static uint8_t
gl518sm_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
gl518sm_i2c_read(void *bus, uint8_t addr, void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
return gl518sm_read(dev, cmd);
}
uint16_t read = gl518sm_read(dev, dev->addr_register);
uint8_t ret = 0;
if ((dev->i2c_state == 1) && (dev->addr_register >= 0x07) && (dev->addr_register <= 0x0c)) { /* two-byte registers: read MSB first */
dev->i2c_state = 2;
ret = read >> 8;
} else
ret = read;
static uint16_t
gl518sm_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
return gl518sm_read(dev, cmd);
dev->addr_register++;
return ret;
}
@@ -157,37 +153,35 @@ gl518sm_read(gl518sm_t *dev, uint8_t reg)
break;
}
/* Duplicate the low byte to the high byte on single-byte registers, although real hardware behavior is undefined. */
if ((reg < 0x07) || (reg > 0x0c))
ret |= ret << 8;
gl518sm_log("GL518SM: read(%02X) = %04X\n", reg, ret);
return ret;
}
static void
gl518sm_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv)
static uint8_t
gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
dev->addr_register = val;
}
switch (dev->i2c_state++) {
case 0:
dev->addr_register = data;
break;
static void
gl518sm_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
gl518sm_write(dev, cmd, val);
}
case 1:
gl518sm_write(dev, dev->addr_register, data);
break;
case 2:
gl518sm_write(dev, dev->addr_register, (data << 8) | gl518sm_read(dev, dev->addr_register));
break;
static void
gl518sm_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv)
{
gl518sm_t *dev = (gl518sm_t *) priv;
gl518sm_write(dev, cmd, val);
default:
return 0;
}
return 1;
}

View File

@@ -30,12 +30,9 @@
#define LM75_TEMP_TO_REG(t) ((t) << 8)
static uint8_t lm75_i2c_read_byte(void *bus, uint8_t addr, void *priv);
static uint8_t lm75_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv);
static uint16_t lm75_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv);
static void lm75_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv);
static void lm75_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
static void lm75_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
static void lm75_i2c_start(void *bus, uint8_t addr, void *priv);
static uint8_t lm75_i2c_read(void *bus, uint8_t addr, void *priv);
static uint8_t lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv);
static void lm75_reset(lm75_t *dev);
@@ -64,61 +61,49 @@ lm75_remap(lm75_t *dev, uint8_t addr)
{
lm75_log("LM75: remapping to I2C %02Xh\n", addr);
if (dev->i2c_addr < 0x80) i2c_removehandler(i2c_smbus, dev->i2c_addr, 1,
NULL, lm75_i2c_read_byte, lm75_i2c_read_byte_cmd, lm75_i2c_read_word_cmd, NULL,
NULL, lm75_i2c_write_byte, lm75_i2c_write_byte_cmd, lm75_i2c_write_word_cmd, NULL,
dev);
if (dev->i2c_addr < 0x80)
i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, lm75_i2c_start, lm75_i2c_read, lm75_i2c_write, NULL, dev);
if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1,
NULL, lm75_i2c_read_byte, lm75_i2c_read_byte_cmd, lm75_i2c_read_word_cmd, NULL,
NULL, lm75_i2c_write_byte, lm75_i2c_write_byte_cmd, lm75_i2c_write_word_cmd, NULL,
dev);
if (addr < 0x80)
i2c_sethandler(i2c_smbus, addr, 1, lm75_i2c_start, lm75_i2c_read, lm75_i2c_write, NULL, dev);
dev->i2c_addr = addr;
}
static uint8_t
lm75_i2c_read_byte(void *bus, uint8_t addr, void *priv)
static void
lm75_i2c_start(void *bus, uint8_t addr, void *priv)
{
lm75_t *dev = (lm75_t *) priv;
return lm75_read(dev, dev->addr_register);
dev->i2c_state = 0;
}
static uint8_t
lm75_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
lm75_i2c_read(void *bus, uint8_t addr, void *priv)
{
lm75_t *dev = (lm75_t *) priv;
return lm75_read(dev, cmd);
}
uint8_t ret = 0;
static uint16_t
lm75_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
{
lm75_t *dev = (lm75_t *) priv;
uint8_t rethi = 0;
uint8_t retlo = 0;
switch (cmd & 0x3) {
switch (dev->addr_register & 0x3) {
case 0x0: /* temperature */
rethi = lm75_read(dev, 0x0);
retlo = lm75_read(dev, 0x1);
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x1 : 0x0);
break;
case 0x1: /* configuration */
rethi = retlo = lm75_read(dev, 0x2);
ret = lm75_read(dev, 0x2);
break;
case 0x2: /* Thyst */
rethi = lm75_read(dev, 0x3);
retlo = lm75_read(dev, 0x4);
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x4 : 0x3);
break;
case 0x3: /* Tos */
rethi = lm75_read(dev, 0x5);
retlo = lm75_read(dev, 0x6);
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x6 : 0x5);
break;
}
return (retlo << 8) | rethi; /* byte-swapped for some reason */
return ret;
}
@@ -130,9 +115,12 @@ lm75_read(lm75_t *dev, uint8_t reg)
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal I2C call, if necessary. */
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80))
ret = i2c_read_byte_cmd(i2c_smbus, dev->as99127f_i2c_addr, reg);
else if ((reg & 0x7) == 0x0) /* temperature high byte */
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
i2c_start(i2c_smbus, dev->as99127f_i2c_addr);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, reg);
ret = i2c_read(i2c_smbus, dev->as99127f_i2c_addr);
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
} else if ((reg & 0x7) == 0x0) /* temperature high byte */
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]) >> 8;
else if ((reg & 0x7) == 0x1) /* temperature low byte */
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]);
@@ -145,47 +133,36 @@ lm75_read(lm75_t *dev, uint8_t reg)
}
static void
lm75_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv)
static uint8_t
lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
{
lm75_t *dev = (lm75_t *) priv;
dev->addr_register = val;
}
if ((dev->i2c_state > 2) || ((dev->i2c_state == 2) && ((dev->addr_register & 0x3) == 0x1))) {
return 0;
} else if (dev->i2c_state == 0) {
dev->addr_register = data;
return 1;
}
static void
lm75_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
{
lm75_t *dev = (lm75_t *) priv;
lm75_write(dev, cmd, val);
}
static void
lm75_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv)
{
lm75_t *dev = (lm75_t *) priv;
uint8_t valhi = (val >> 8);
uint8_t vallo = (val & 0xff);
switch (cmd & 0x3) {
switch (dev->addr_register & 0x3) {
case 0x0: /* temperature */
lm75_write(dev, 0x0, valhi);
lm75_write(dev, 0x1, vallo);
lm75_write(dev, (dev->i2c_state == 1) ? 0x1 : 0x0, data);
break;
case 0x1: /* configuration */
lm75_write(dev, 0x2, vallo);
lm75_write(dev, 0x2, data);
break;
case 0x2: /* Thyst */
lm75_write(dev, 0x3, valhi);
lm75_write(dev, 0x4, vallo);
lm75_write(dev, (dev->i2c_state == 1) ? 0x4 : 0x3, data);
break;
case 0x3: /* Tos */
lm75_write(dev, 0x5, valhi);
lm75_write(dev, 0x6, vallo);
lm75_write(dev, (dev->i2c_state == 1) ? 0x6 : 0x5, data);
break;
break;
}
return 1;
}
@@ -198,7 +175,10 @@ lm75_write(lm75_t *dev, uint8_t reg, uint8_t val)
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal I2C call, if necessary. */
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
i2c_write_byte_cmd(i2c_smbus, dev->as99127f_i2c_addr, reg, val);
i2c_start(i2c_smbus, dev->as99127f_i2c_addr);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, reg);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, val);
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
return 1;
}

View File

@@ -56,19 +56,16 @@ typedef struct {
uint8_t addr_register;
uint8_t data_register;
uint8_t i2c_addr;
uint8_t i2c_addr, i2c_state;
} lm78_t;
static void lm78_i2c_start(void *bus, uint8_t addr, void *priv);
static uint8_t lm78_isa_read(uint16_t port, void *priv);
static uint8_t lm78_i2c_read_byte(void *bus, uint8_t addr, void *priv);
static uint8_t lm78_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv);
static uint16_t lm78_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv);
static uint8_t lm78_i2c_read(void *bus, uint8_t addr, void *priv);
static uint8_t lm78_read(lm78_t *dev, uint8_t reg, uint8_t bank);
static void lm78_isa_write(uint16_t port, uint8_t val, void *priv);
static void lm78_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv);
static void lm78_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
static void lm78_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
static uint8_t lm78_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv);
static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank);
static void lm78_reset(lm78_t *dev, uint8_t initialization);
@@ -100,17 +97,12 @@ lm78_remap(lm78_t *dev, uint8_t addr)
if (!(dev->local & LM78_I2C)) return;
lm78_log("LM78: remapping to I2C %02Xh\n", addr);
lm78_log("LM78: remapping to SMBus %02Xh\n", addr);
i2c_removehandler(i2c_smbus, dev->i2c_addr, 1,
NULL, lm78_i2c_read_byte, lm78_i2c_read_byte_cmd, lm78_i2c_read_word_cmd, NULL,
NULL, lm78_i2c_write_byte, lm78_i2c_write_byte_cmd, lm78_i2c_write_word_cmd, NULL,
dev);
i2c_removehandler(i2c_smbus, dev->i2c_addr, 1, lm78_i2c_start, lm78_i2c_read, lm78_i2c_write, NULL, dev);
if (addr < 0x80) i2c_sethandler(i2c_smbus, addr, 1,
NULL, lm78_i2c_read_byte, lm78_i2c_read_byte_cmd, lm78_i2c_read_word_cmd, NULL,
NULL, lm78_i2c_write_byte, lm78_i2c_write_byte_cmd, lm78_i2c_write_word_cmd, NULL,
dev);
if (addr < 0x80)
i2c_sethandler(i2c_smbus, addr, 1, lm78_i2c_start, lm78_i2c_read, lm78_i2c_write, NULL, dev);
dev->i2c_addr = addr;
@@ -126,6 +118,15 @@ lm78_remap(lm78_t *dev, uint8_t addr)
}
static void
lm78_i2c_start(void *bus, uint8_t addr, void *priv)
{
lm78_t *dev = (lm78_t *) priv;
dev->i2c_state = 0;
}
static uint8_t
lm78_isa_read(uint16_t port, void *priv)
{
@@ -159,26 +160,11 @@ lm78_isa_read(uint16_t port, void *priv)
static uint8_t
lm78_i2c_read_byte(void *bus, uint8_t addr, void *priv)
lm78_i2c_read(void *bus, uint8_t addr, void *priv)
{
lm78_t *dev = (lm78_t *) priv;
return lm78_read(dev, dev->addr_register, LM78_WINBOND_BANK);
}
static uint8_t
lm78_i2c_read_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
{
lm78_t *dev = (lm78_t *) priv;
return lm78_read(dev, cmd, LM78_WINBOND_BANK);
}
static uint16_t
lm78_i2c_read_word_cmd(void *bus, uint8_t addr, uint8_t cmd, void *priv)
{
lm78_t *dev = (lm78_t *) priv;
return (lm78_read(dev, cmd, LM78_WINBOND_BANK) << 8) | lm78_read(dev, cmd, LM78_WINBOND_BANK);
return lm78_read(dev, dev->addr_register++, LM78_WINBOND_BANK);
}
@@ -264,27 +250,18 @@ lm78_isa_write(uint16_t port, uint8_t val, void *priv)
}
static void
lm78_i2c_write_byte(void *bus, uint8_t addr, uint8_t val, void *priv)
static uint8_t
lm78_i2c_write(void *bus, uint8_t addr, uint8_t val, void *priv)
{
lm78_t *dev = (lm78_t *) priv;
dev->addr_register = val;
}
if (dev->i2c_state == 0) {
dev->i2c_state = 1;
dev->addr_register = val;
} else
lm78_write(dev, dev->addr_register++, val, LM78_WINBOND_BANK);
static void
lm78_i2c_write_byte_cmd(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv)
{
lm78_t *dev = (lm78_t *) priv;
lm78_write(dev, cmd, val, LM78_WINBOND_BANK);
}
static void
lm78_i2c_write_word_cmd(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv)
{
lm78_t *dev = (lm78_t *) priv;
lm78_write(dev, cmd, val, LM78_WINBOND_BANK);
return 1;
}

View File

@@ -6,7 +6,7 @@
*
* This file is part of the 86Box distribution.
*
* Implement the I2C bus and its operations.
* Implementation of the I2C bus and its operations.
*
*
*
@@ -30,17 +30,10 @@
typedef struct _i2c_ {
void (*read_quick)(void *bus, uint8_t addr, void *priv);
uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv);
uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv);
uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv);
uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv);
void (*write_quick)(void *bus, uint8_t addr, void *priv);
void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv);
void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv);
void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv);
void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv);
void (*start)(void *bus, uint8_t addr, void *priv);
uint8_t (*read)(void *bus, uint8_t addr, void *priv);
uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv);
void (*stop)(void *bus, uint8_t addr, void *priv);
void *priv;
@@ -55,7 +48,7 @@ typedef struct {
void *i2c_smbus;
#define ENABLE_I2C_LOG 1
#ifdef ENABLE_I2C_LOG
int i2c_do_log = ENABLE_I2C_LOG;
@@ -100,16 +93,10 @@ i2c_removebus(void *bus_handle)
void
i2c_sethandler(void *bus_handle, uint8_t base, int size,
void (*read_quick)(void *bus, uint8_t addr, void *priv),
uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv),
uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv),
uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv),
uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv),
void (*write_quick)(void *bus, uint8_t addr, void *priv),
void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv),
void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv),
void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv),
void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv),
void (*start)(void *bus, uint8_t addr, void *priv),
uint8_t (*read)(void *bus, uint8_t addr, void *priv),
uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv),
void (*stop)(void *bus, uint8_t addr, void *priv),
void *priv)
{
int c;
@@ -131,15 +118,10 @@ i2c_sethandler(void *bus_handle, uint8_t base, int size,
q->prev = NULL;
}
q->read_byte = read_byte;
q->read_byte_cmd = read_byte_cmd;
q->read_word_cmd = read_word_cmd;
q->read_block_cmd = read_block_cmd;
q->write_byte = write_byte;
q->write_byte_cmd = write_byte_cmd;
q->write_word_cmd = write_word_cmd;
q->write_block_cmd = write_block_cmd;
q->start = start;
q->read = read;
q->write = write;
q->stop = stop;
q->priv = priv;
q->next = NULL;
@@ -151,16 +133,10 @@ i2c_sethandler(void *bus_handle, uint8_t base, int size,
void
i2c_removehandler(void *bus_handle, uint8_t base, int size,
void (*read_quick)(void *bus, uint8_t addr, void *priv),
uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv),
uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv),
uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv),
uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv),
void (*write_quick)(void *bus, uint8_t addr, void *priv),
void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv),
void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv),
void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv),
void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv),
void (*start)(void *bus, uint8_t addr, void *priv),
uint8_t (*read)(void *bus, uint8_t addr, void *priv),
uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv),
void (*stop)(void *bus, uint8_t addr, void *priv),
void *priv)
{
int c;
@@ -176,11 +152,7 @@ i2c_removehandler(void *bus_handle, uint8_t base, int size,
continue;
while(p) {
q = p->next;
if ((p->read_byte == read_byte) && (p->read_byte_cmd == read_byte_cmd) &&
(p->read_word_cmd == read_word_cmd) && (p->read_block_cmd == read_block_cmd) &&
(p->write_byte == write_byte) && (p->write_byte_cmd == write_byte_cmd) &&
(p->write_word_cmd == write_word_cmd) && (p->write_block_cmd == write_block_cmd) &&
(p->priv == priv)) {
if ((p->read == read) && (p->write == write) && (p->priv == priv)) {
if (p->prev)
p->prev->next = p->next;
else
@@ -201,22 +173,16 @@ i2c_removehandler(void *bus_handle, uint8_t base, int size,
void
i2c_handler(int set, void *bus_handle, uint8_t base, int size,
void (*read_quick)(void *bus, uint8_t addr, void *priv),
uint8_t (*read_byte)(void *bus, uint8_t addr, void *priv),
uint8_t (*read_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv),
uint16_t (*read_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, void *priv),
uint8_t (*read_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv),
void (*write_quick)(void *bus, uint8_t addr, void *priv),
void (*write_byte)(void *bus, uint8_t addr, uint8_t val, void *priv),
void (*write_byte_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t val, void *priv),
void (*write_word_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint16_t val, void *priv),
void (*write_block_cmd)(void *bus, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv),
void (*start)(void *bus, uint8_t addr, void *priv),
uint8_t (*read)(void *bus, uint8_t addr, void *priv),
uint8_t (*write)(void *bus, uint8_t addr, uint8_t data, void *priv),
void (*stop)(void *bus, uint8_t addr, void *priv),
void *priv)
{
if (set)
i2c_sethandler(bus_handle, base, size, read_quick, read_byte, read_byte_cmd, read_word_cmd, read_block_cmd, write_quick, write_byte, write_byte_cmd, write_word_cmd, write_block_cmd, priv);
i2c_sethandler(bus_handle, base, size, start, read, write, stop, priv);
else
i2c_removehandler(bus_handle, base, size, read_quick, read_byte, read_byte_cmd, read_word_cmd, read_block_cmd, write_quick, write_byte, write_byte_cmd, write_word_cmd, write_block_cmd, priv);
i2c_removehandler(bus_handle, base, size, start, read, write, stop, priv);
}
@@ -233,11 +199,10 @@ i2c_has_device(void *bus_handle, uint8_t addr)
void
i2c_read_quick(void *bus_handle, uint8_t addr)
i2c_start(void *bus_handle, uint8_t addr)
{
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
i2c_t *p;
int found = 0;
if (!bus)
return;
@@ -245,106 +210,23 @@ i2c_read_quick(void *bus_handle, uint8_t addr)
p = bus->devices[addr];
if (p) {
while(p) {
if (p->read_byte) {
p->read_quick(bus_handle, addr, p->priv);
found++;
if (p->start) {
p->start(bus_handle, addr, p->priv);
}
p = p->next;
}
}
i2c_log("I2C: read_quick(%s, %02X)\n", bus->name, addr);
i2c_log("I2C: start(%s, %02X)\n", bus->name, addr);
}
uint8_t
i2c_read_byte(void *bus_handle, uint8_t addr)
{
uint8_t ret = 0xff;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
i2c_t *p;
int found = 0;
if (!bus)
return(ret);
p = bus->devices[addr];
if (p) {
while(p) {
if (p->read_byte) {
ret &= p->read_byte(bus_handle, addr, p->priv);
found++;
}
p = p->next;
}
}
i2c_log("I2C: read_byte(%s, %02X) = %02X\n", bus->name, addr, ret);
return(ret);
}
uint8_t
i2c_read_byte_cmd(void *bus_handle, uint8_t addr, uint8_t cmd)
{
uint8_t ret = 0xff;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
i2c_t *p;
int found = 0;
if (!bus)
return(ret);
p = bus->devices[addr];
if (p) {
while(p) {
if (p->read_byte_cmd) {
ret &= p->read_byte_cmd(bus_handle, addr, cmd, p->priv);
found++;
}
p = p->next;
}
}
i2c_log("I2C: read_byte_cmd(%s, %02X, %02X) = %02X\n", bus->name, addr, cmd, ret);
return(ret);
}
uint16_t
i2c_read_word_cmd(void *bus_handle, uint8_t addr, uint8_t cmd)
{
uint16_t ret = 0xffff;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
i2c_t *p;
int found = 0;
if (!bus)
return(ret);
p = bus->devices[addr];
if (p) {
while(p) {
if (p->read_word_cmd) {
ret &= p->read_word_cmd(bus_handle, addr, cmd, p->priv);
found++;
}
p = p->next;
}
}
i2c_log("I2C: read_word_cmd(%s, %02X, %02X) = %04X\n", bus->name, addr, cmd, ret);
return(ret);
}
uint8_t
i2c_read_block_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len)
i2c_read(void *bus_handle, uint8_t addr)
{
uint8_t ret = 0;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
i2c_t *p;
int found = 0;
if (!bus)
return(ret);
@@ -352,26 +234,51 @@ i2c_read_block_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t *data, u
p = bus->devices[addr];
if (p) {
while(p) {
if (p->read_block_cmd) {
ret = MAX(ret, p->read_block_cmd(bus_handle, addr, cmd, data, len, p->priv));
found++;
if (p->read) {
ret = p->read(bus_handle, addr, p->priv);
break;
}
p = p->next;
}
}
i2c_log("I2C: read_block_cmd(%s, %02X, %02X) = %02X\n", bus->name, addr, cmd, len);
i2c_log("I2C: read(%s, %02X) = %02X\n", bus->name, addr, ret);
return(ret);
}
uint8_t
i2c_write(void *bus_handle, uint8_t addr, uint8_t data)
{
uint8_t ret = 0;
i2c_t *p;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
if (!bus)
return(ret);
p = bus->devices[addr];
if (p) {
while(p) {
if (p->write) {
ret = p->write(bus_handle, addr, data, p->priv);
}
p = p->next;
}
}
i2c_log("I2C: write(%s, %02X, %02X) = %d\n", bus->name, addr, data, ret);
return(ret);
}
void
i2c_write_quick(void *bus_handle, uint8_t addr)
i2c_stop(void *bus_handle, uint8_t addr)
{
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
i2c_t *p;
int found = 0;
if (!bus)
return;
@@ -379,118 +286,12 @@ i2c_write_quick(void *bus_handle, uint8_t addr)
p = bus->devices[addr];
if (p) {
while(p) {
if (p->read_byte) {
p->write_quick(bus_handle, addr, p->priv);
found++;
if (p->stop) {
p->stop(bus_handle, addr, p->priv);
}
p = p->next;
}
}
i2c_log("I2C: write_quick(%s, %02X)\n", bus->name, addr);
}
void
i2c_write_byte(void *bus_handle, uint8_t addr, uint8_t val)
{
i2c_t *p;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
int found = 0;
if (!bus)
return;
if (bus->devices[addr]) {
p = bus->devices[addr];
while(p) {
if (p->write_byte) {
p->write_byte(bus_handle, addr, val, p->priv);
found++;
}
p = p->next;
}
}
i2c_log("I2C: write_byte(%s, %02X, %02X)\n", bus->name, addr, val);
return;
}
void
i2c_write_byte_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t val)
{
i2c_t *p;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
int found = 0;
if (!bus)
return;
if (bus->devices[addr]) {
p = bus->devices[addr];
while(p) {
if (p->write_byte_cmd) {
p->write_byte_cmd(bus_handle, addr, cmd, val, p->priv);
found++;
}
p = p->next;
}
}
i2c_log("I2C: write_byte_cmd(%s, %02X, %02X, %02X)\n", bus->name, addr, cmd, val);
return;
}
void
i2c_write_word_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint16_t val)
{
i2c_t *p;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
int found = 0;
if (!bus)
return;
if (bus->devices[addr]) {
p = bus->devices[addr];
while(p) {
if (p->write_word_cmd) {
p->write_word_cmd(bus_handle, addr, cmd, val, p->priv);
found++;
}
p = p->next;
}
}
i2c_log("I2C: write_word_cmd(%s, %02X, %02X, %04X)\n", bus->name, addr, cmd, val);
return;
}
void
i2c_write_block_cmd(void *bus_handle, uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len)
{
i2c_t *p;
i2c_bus_t *bus = (i2c_bus_t *) bus_handle;
int found = 0;
if (!bus)
return;
p = bus->devices[addr];
if (p) {
while(p) {
if (p->write_block_cmd) {
p->write_block_cmd(bus_handle, addr, cmd, data, len, p->priv);
found++;
}
p = p->next;
}
}
i2c_log("I2C: write_block_cmd(%s, %02X, %02X, %02X)\n", bus->name, addr, cmd, len);
return;
i2c_log("I2C: stop(%s, %02X)\n", bus->name, addr);
}

102
src/device/i2c_eeprom.c Normal file
View File

@@ -0,0 +1,102 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Emulation of the AT24Cxx series of I2C EEPROMs.
*
*
*
* Authors: RichardG, <richardg867@gmail.com>
*
* Copyright 2020 RichardG.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define HAVE_STDARG_H
#include <wchar.h>
#include <86box/86box.h>
#include <86box/i2c.h>
typedef struct {
void *i2c;
uint8_t addr;
uint8_t *data;
uint8_t writable;
uint16_t addr_mask;
uint8_t addr_register;
uint8_t i2c_state;
} i2c_eeprom_t;
void
i2c_eeprom_start(void *bus, uint8_t addr, void *priv)
{
i2c_eeprom_t *dev = (i2c_eeprom_t *) priv;
dev->i2c_state = 0;
}
uint8_t
i2c_eeprom_read(void *bus, uint8_t addr, void *priv)
{
i2c_eeprom_t *dev = (i2c_eeprom_t *) priv;
return dev->data[((addr << 8) | dev->addr_register++) & dev->addr_mask];
}
uint8_t
i2c_eeprom_write(void *bus, uint8_t addr, uint8_t data, void *priv)
{
i2c_eeprom_t *dev = (i2c_eeprom_t *) priv;
if (dev->i2c_state == 0) {
dev->i2c_state = 1;
dev->addr_register = data;
} else if (dev->writable)
dev->data[((addr << 8) | dev->addr_register++) & dev->addr_mask] = data;
else
return 0;
return 1;
}
void *
i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint16_t size, uint8_t writable)
{
i2c_eeprom_t *dev = (i2c_eeprom_t *) malloc(sizeof(i2c_eeprom_t));
memset(dev, 0, sizeof(i2c_eeprom_t));
dev->i2c = i2c;
dev->addr = addr;
dev->data = data;
dev->writable = writable;
dev->addr_mask = size - 1;
i2c_sethandler(i2c, dev->addr & ~(dev->addr_mask >> 8), (dev->addr_mask >> 8) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev);
return dev;
}
void
i2c_eeprom_close(void *dev_handle)
{
i2c_eeprom_t *dev = (i2c_eeprom_t *) dev_handle;
i2c_removehandler(dev->i2c, dev->addr & ~(dev->addr_mask >> 8), (dev->addr_mask >> 8) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev);
free(dev);
}

View File

@@ -6,7 +6,7 @@
*
* This file is part of the 86Box distribution.
*
* Implementation of a GPIO-based I2C device.
* Emulation of a GPIO-based I2C device.
*
*
*
@@ -16,13 +16,13 @@
* Copyright 2008-2020 Sarah Walker.
* Copyright 2020 RichardG.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#define HAVE_STDARG_H
#include <wchar.h>
#include <math.h>
#include <86box/86box.h>
#include <86box/i2c.h>
@@ -53,8 +53,8 @@ enum {
typedef struct {
void *i2c;
uint8_t scl, sda, state, slave_state, slave_addr, slave_reg,
slave_writing, slave_rw, last_sda, pos, transmit, byte;
uint8_t scl, sda, state, slave_state, slave_addr,
slave_rw, last_sda, pos, transmit, byte;
} i2c_gpio_t;
@@ -66,6 +66,7 @@ i2c_gpio_init(char *bus_name)
dev->i2c = i2c_addbus(bus_name);
dev->scl = dev->sda = 1;
dev->slave_addr = 0xff;
return dev;
}
@@ -85,49 +86,46 @@ i2c_gpio_close(void *dev_handle)
void
i2c_gpio_next_byte(i2c_gpio_t *dev)
{
dev->byte = i2c_read_byte(dev->i2c, dev->slave_addr);
dev->byte = i2c_read(dev->i2c, dev->slave_addr);
}
void
i2c_gpio_write(i2c_gpio_t *dev)
{
uint8_t i;
switch (dev->slave_state) {
case SLAVE_IDLE:
i = dev->slave_addr;
dev->slave_addr = dev->byte >> 1;
dev->slave_rw = dev->byte & 1;
if (!i2c_has_device(dev->i2c, dev->slave_addr)) {
dev->slave_state = SLAVE_INVALID;
break;
}
dev->slave_rw = dev->byte & 1;
dev->slave_writing = 0;
if (i == 0xff)
i2c_start(dev->i2c, dev->slave_addr);
if (dev->slave_rw) {
dev->slave_state = SLAVE_SENDDATA;
dev->transmit = TRANSMITTER_SLAVE;
dev->byte = i2c_read_byte(dev->i2c, dev->slave_addr);
dev->byte = i2c_read(dev->i2c, dev->slave_addr);
} else {
dev->slave_state = SLAVE_RECEIVEADDR;
dev->transmit = TRANSMITTER_MASTER;
}
pclog("slave_idle %02X %d\n", dev->slave_addr, dev->slave_rw);
break;
case SLAVE_RECEIVEADDR:
pclog("slave_receiveaddr %02X %d\n", dev->slave_addr, dev->slave_rw);
i2c_write_byte(dev->i2c, dev->slave_addr, dev->byte);
dev->slave_writing = 1;
dev->slave_reg = dev->byte;
i2c_write(dev->i2c, dev->slave_addr, dev->byte);
dev->slave_state = dev->slave_rw ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA;
break;
case SLAVE_RECEIVEDATA:
pclog("slave_receivedata %02X %d = %02X\n", dev->slave_addr, dev->slave_rw, dev->byte);
dev->slave_writing = 0;
i2c_write_byte_cmd(dev->i2c, dev->slave_addr, dev->slave_reg, dev->byte);
break;
case SLAVE_SENDDATA:
pclog("slave_senddata %02X %d = %02X\n", dev->slave_addr, dev->slave_rw, dev->byte);
i2c_write(dev->i2c, dev->slave_addr, dev->byte);
break;
}
}
@@ -136,10 +134,9 @@ i2c_gpio_write(i2c_gpio_t *dev)
void
i2c_gpio_stop(i2c_gpio_t *dev)
{
pclog("stopping... state = %d\n", dev->slave_state);
if (dev->slave_writing)
i2c_write_byte(dev->i2c, dev->slave_addr, dev->slave_reg);
i2c_stop(dev->i2c, dev->slave_addr);
dev->slave_addr = 0xff;
dev->slave_state = SLAVE_IDLE;
dev->transmit = TRANSMITTER_MASTER;
}

View File

@@ -99,7 +99,6 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
{
smbus_piix4_t *dev = (smbus_piix4_t *) priv;
uint8_t smbus_addr, smbus_read, prev_stat;
uint16_t temp;
smbus_piix4_log("SMBus PIIX4: write(%02X, %02X)\n", addr, val);
@@ -132,46 +131,53 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
}
smbus_read = dev->addr & 0x01;
/* start transaction */
i2c_start(i2c_smbus, smbus_addr);
/* decode the 3-bit command protocol */
dev->next_stat = 0x2; /* raise INTER (command completed) by default */
switch ((val >> 2) & 0x7) {
case 0x0: /* quick R/W */
if (smbus_read)
i2c_read_quick(i2c_smbus, smbus_addr);
else
i2c_write_quick(i2c_smbus, smbus_addr);
break;
case 0x1: /* byte R/W */
if (smbus_read)
dev->data0 = i2c_read_byte(i2c_smbus, smbus_addr);
dev->data0 = i2c_read(i2c_smbus, smbus_addr);
else
i2c_write_byte(i2c_smbus, smbus_addr, dev->data0);
i2c_write(i2c_smbus, smbus_addr, dev->data0);
break;
case 0x2: /* byte data R/W */
i2c_write(i2c_smbus, smbus_addr, dev->cmd);
if (smbus_read)
dev->data0 = i2c_read_byte_cmd(i2c_smbus, smbus_addr, dev->cmd);
dev->data0 = i2c_read(i2c_smbus, smbus_addr);
else
i2c_write_byte_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data0);
i2c_write(i2c_smbus, smbus_addr, dev->data0);
break;
case 0x3: /* word data R/W */
i2c_write(i2c_smbus, smbus_addr, dev->cmd);
if (smbus_read) {
temp = i2c_read_word_cmd(i2c_smbus, smbus_addr, dev->cmd);
dev->data0 = temp;
dev->data1 = temp >> 8;
dev->data0 = i2c_read(i2c_smbus, smbus_addr);
dev->data1 = i2c_read(i2c_smbus, smbus_addr);
} else {
temp = (dev->data1 << 8) | dev->data0;
i2c_write_word_cmd(i2c_smbus, smbus_addr, dev->cmd, temp);
i2c_write(i2c_smbus, smbus_addr, dev->data0);
i2c_write(i2c_smbus, smbus_addr, dev->data1);
}
break;
case 0x5: /* block R/W */
if (smbus_read)
dev->data0 = i2c_read_block_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data, SMBUS_PIIX4_BLOCK_DATA_SIZE);
else
i2c_write_block_cmd(i2c_smbus, smbus_addr, dev->cmd, dev->data, dev->data0);
i2c_write(i2c_smbus, smbus_addr, dev->cmd);
/* SMBus block data is preceded by a length */
if (smbus_read) {
dev->data0 = i2c_read(i2c_smbus, smbus_addr);
for (smbus_read = 0; smbus_read < MIN(SMBUS_PIIX4_BLOCK_DATA_SIZE, dev->data0); smbus_read++)
dev->data[smbus_read] = i2c_read(i2c_smbus, smbus_addr);
} else {
i2c_write(i2c_smbus, smbus_addr, dev->data0);
for (smbus_read = 0; smbus_read < MIN(SMBUS_PIIX4_BLOCK_DATA_SIZE, dev->data0); smbus_read++)
i2c_write(i2c_smbus, smbus_addr, dev->data[smbus_read]);
}
break;
default:
@@ -179,6 +185,9 @@ smbus_piix4_write(uint16_t addr, uint8_t val, void *priv)
dev->next_stat = 0x4;
break;
}
/* stop transaction */
i2c_stop(i2c_smbus, smbus_addr);
}
break;
@@ -244,7 +253,7 @@ smbus_piix4_init(const device_t *info)
smbus_piix4_t *dev = (smbus_piix4_t *) malloc(sizeof(smbus_piix4_t));
memset(dev, 0, sizeof(smbus_piix4_t));
i2c_smbus = i2c_addbus("smbus_piix4");
i2c_smbus = dev->i2c = i2c_addbus("smbus_piix4");
timer_add(&dev->response_timer, smbus_piix4_response, dev, 0);
@@ -257,8 +266,9 @@ smbus_piix4_close(void *priv)
{
smbus_piix4_t *dev = (smbus_piix4_t *) priv;
i2c_removebus(i2c_smbus);
i2c_smbus = NULL;
if (i2c_smbus == dev->i2c)
i2c_smbus = NULL;
i2c_removebus(dev->i2c);
free(dev);
}