I2C overhaul part 2
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
327
src/device/i2c.c
327
src/device/i2c.c
@@ -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
102
src/device/i2c_eeprom.c
Normal 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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user